6.3 KiB
智能核心模块详细设计
1. 模块目标
Agent Core 提供独立于 Django View 的智能编排能力。它消费场景配置,执行 RAG、工具、模型调用和结构化解析,最终返回统一 AgentResult。
2. 职责边界
负责:
- Agent 编排。
- 场景配置对象消费。
- RAG 入库和检索。
- 工具注册与执行。
- LLM Provider 与 Embedding Provider。
- 结构化输出解析。
- AgentResult 定义。
不负责:
- 不渲染页面。
- 不处理 Django 表单。
- 不保存 Django Model。
- 不管理登录权限。
3. 子模块划分
agent_core/
orchestrator.py
scenario_loader.py
llm_provider.py
tool_registry.py
structured_output.py
rag/
ingest.py
retriever.py
tools/
builtin_tools.py
schemas/
outputs.py
scenario_loader.py 可作为非 Django 环境下加载配置的工具;Django 场景展示仍由 apps.scenarios 负责。
4. Orchestrator 设计
入口:
def run_agent(scenario_config, user_input: str, options: dict | None = None) -> AgentResult:
"""执行一次 Agent 编排,options 可包含 document_ids 等运行期约束。"""
流程:
- 记录开始时间。
- 根据
rag.enabled、scenario_id和可选document_ids检索引用。 - 根据
tools执行或准备工具结果。 - 构造 messages。
- 调用 LLM Provider。
- 解析结构化输出。
- 计算耗时。
- 返回
AgentResult(status="success")。 - 捕获可恢复异常并返回
status="failed"。
V1 在缺少 LLM 或 Embedding 配置时必须返回清晰失败结果。测试代码可以使用 mock provider,但 V1 验收链路必须通过真实 OpenAI 兼容 LLM、Embedding 和 Chroma。
5. Scenario Loader 设计
Agent Core 的 Scenario Loader 用于脚本、测试或后续独立服务场景。它不依赖 Django View,可以复用 Scenarios 模块的字段规范。
接口:
load_scenario(path: str) -> dict
load_scenarios(directory: str) -> list[dict]
6. RAG 设计
入库接口:
def ingest_document(
document_id: int,
scenario_id: str,
source_file: str,
text: str,
collection: str,
) -> IngestResult:
"""切分文档、生成 embedding,并写入 Chroma。重新入库时覆盖同一 document_id 的旧 chunk。"""
检索接口:
def retrieve(
scenario_id: str,
query: str,
collection: str,
top_k: int = 5,
document_ids: list[int] | None = None,
) -> list[ReferenceChunk]:
"""按场景和可选文档范围执行向量检索,返回可审计引用片段。"""
切分策略:
- 默认 chunk size 800 到 1000 字。
- overlap 100 到 150 字。
- metadata 包含
scenario_id、document_id、source_file、chunk_id。
RAG 入库和检索必须使用 Embedding Provider 与 Chroma。单元测试桩或开发阶段临时验证方案不属于 V1 验收设计。
7. Tool Registry 设计
工具注册:
registry.register("calculate_rate", calculate_rate)
registry.get("calculate_rate")
registry.run("calculate_rate", **kwargs)
工具结果统一:
{
"tool_name": "calculate_rate",
"success": true,
"arguments": {},
"result": {},
"error": ""
}
内置工具:
calculate_ratequery_demo_recordscheck_required_fieldsgenerate_action_items
工具函数不得直接读取 API Key 或执行无审计的外部副作用。
8. LLM Provider 设计
接口:
class LLMProvider:
def generate(self, messages: list[dict], response_format: dict | None = None) -> LLMResponse:
"""调用 OpenAI 兼容 Chat Completions 接口并返回统一响应对象。"""
配置来源:
LLM_API_KEYLLM_BASE_URLLLM_MODEL
Provider 对外隐藏供应商差异,Orchestrator 只处理 LLMResponse.content、LLMResponse.model_name 和错误信息。供应商可自主选择 OpenAI、硅基流动等 OpenAI 兼容服务。
Embedding Provider 接口:
class EmbeddingProvider:
def embed_texts(self, texts: list[str]) -> list[list[float]]:
"""调用 OpenAI 兼容 Embeddings 接口,返回与输入文本一一对应的向量。"""
配置来源:
EMBEDDING_API_KEYEMBEDDING_BASE_URLEMBEDDING_MODEL
当 EMBEDDING_API_KEY 或 EMBEDDING_BASE_URL 为空时,可以复用 LLM_API_KEY 和 LLM_BASE_URL。
9. Structured Output 设计
接口:
def parse_structured_output(raw_output: str, output_type: str) -> ParseResult:
"""优先解析 JSON,并根据输出类型返回结构化结果或解析错误。"""
策略:
- 优先解析 JSON。
- 根据
output_type做字段补齐或轻校验。 - 失败时返回
success=False,保留raw_output。 - 不因结构化解析失败导致整个 Agent 流程崩溃。
10. AgentResult 设计
建议 dataclass:
@dataclass
class AgentResult:
answer: str
structured_output: dict
references: list
tool_calls: list
raw_output: str
model_name: str
latency_ms: int
status: str
error: str = ""
所有字段必须有默认值或构造时明确传入,保证 Audit 模块写入稳定。
11. Adapter 扩展设计
统一接口:
class AgentEngine:
def run_agent(self, scenario_config, user_input: str, options: dict | None = None) -> AgentResult:
"""保持与顶层 run_agent 函数一致的输入输出合约。"""
V1 实现:
LightweightOrchestrator
后续扩展:
DifyAdapterOpenAIAgentsAdapterLangGraphAdapter
Adapter 只能替换编排实现,不能改变 Django 层依赖的 AgentResult 合约。
12. 异常处理
| 异常 | 处理 |
|---|---|
| RAG 检索失败 | 记录错误,允许继续或返回 failed |
| 工具不存在 | 记录失败工具调用 |
| 工具执行异常 | 捕获并返回失败工具结果 |
| LLM 配置缺失 | 返回 failed AgentResult |
| LLM 调用失败 | 返回 failed AgentResult |
| JSON 解析失败 | 返回 success 但带解析错误,展示 raw output |
13. 验收标准
- Chat 可以调用
run_agent()。 - 返回对象字段稳定完整。
- RAG 按
scenario_id隔离。 - RAG 支持按
document_ids限定本次对话的文档范围。 - 工具调用结果格式统一。
- LLM 与 Embedding 配置从环境变量读取。
- 结构化解析失败不导致页面崩溃。
- Agent Core 不依赖 Django View。