2026-09-09 21:55:37 +08:00
|
|
|
|
# Agent 底座使用文档
|
|
|
|
|
|
|
|
|
|
|
|
> 版本:v1.0
|
|
|
|
|
|
> 适用范围:底座负责人、业务 Agent 开发人员、接口联调人员
|
|
|
|
|
|
> 当前运行方式:FastAPI + MySQL + 独立 Worker + Redis/Milvus/Neo4j 可选基础设施
|
|
|
|
|
|
|
|
|
|
|
|
本文说明如何启动底座、注册业务 Agent、提交运行、读取结果,以及如何使用记忆、配置、模型路由和公共会话能力。
|
|
|
|
|
|
接口字段的最终权威定义仍是《05-接口文档.md》,数据库的最终权威定义仍是《00-新数据库基线设计.md》和《02-数据库建表设计.md》。
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 运行前提
|
|
|
|
|
|
|
2026-09-11 14:37:20 +08:00
|
|
|
|
项目固定使用项目自带虚拟环境(Python 3.13,实测 3.13.5):
|
2026-09-09 21:55:37 +08:00
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe --version
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
首次安装依赖:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
项目依赖的 `.env` 不提交到代码仓库。可以复制模板后填写本机配置:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
|
Copy-Item .env.example .env
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
至少需要配置:
|
|
|
|
|
|
|
|
|
|
|
|
```dotenv
|
|
|
|
|
|
JWT_ISSUER=jr-local
|
|
|
|
|
|
JWT_AUDIENCE=jr-agent-platform
|
2026-09-10 18:18:00 +08:00
|
|
|
|
JWT_PUBLIC_KEY_PATH=config/jwt/dev/jwt-public.pem
|
2026-09-09 21:55:37 +08:00
|
|
|
|
MYSQL_DSN=mysql+asyncmy://用户名:密码@127.0.0.1:3306/jr
|
|
|
|
|
|
REDIS_URL=redis://127.0.0.1:6379/0
|
|
|
|
|
|
MILVUS_URI=http://127.0.0.1:19530
|
|
|
|
|
|
NEO4J_URI=bolt://127.0.0.1:7687
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
JWT 私钥只用于签发测试 Token,服务端只读取公钥。模型密钥通过 `secret_ref` 引用环境变量或密钥服务,不能写入 `.py`、数据库明文字段或日志。
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 数据库和迁移
|
|
|
|
|
|
|
|
|
|
|
|
迁移由 Alembic 执行,业务代码不会在运行时创建表:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe -m alembic upgrade head
|
|
|
|
|
|
.\.venv\Scripts\python.exe tools\audit_schema.py
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-11 14:37:20 +08:00
|
|
|
|
当前数据库共 52 张表,其中 **51 张业务表**(另有 Alembic 版本表 `alembic_version`,不计入业务表口径)。
|
|
|
|
|
|
`tools/audit_schema.py` 的实测输出即 `schema audit passed: 51 business tables, no missing or unexpected tables`。
|
2026-09-09 21:55:37 +08:00
|
|
|
|
|
2026-09-11 14:37:20 +08:00
|
|
|
|
51 张业务表相对同一批迁移构建的基线是:
|
|
|
|
|
|
|
|
|
|
|
|
- 49 张基线和已落地表(2026-09-09 补建会话表之前保存的 49 张表指纹即该口径,
|
|
|
|
|
|
见 `docs/08-数据库结构审计基线.md` §二);
|
|
|
|
|
|
- `svc_conversation_session` 会话表(迁移 `20260909_session`,是 2026-09-09 那次 49 张之后的第 1 张新增表);
|
|
|
|
|
|
- `api_request_receipt` 公共 HTTP 写操作幂等回执表(迁移 `20260909_api_receipt`,第 2 张新增表)。
|
|
|
|
|
|
|
|
|
|
|
|
> 口径提醒:`docs/08` §三 记录的「纠偏前 52 张表快照」是 `SHOW CREATE TABLE` 全量表数,
|
|
|
|
|
|
> 含 `alembic_version`,与上面的 51 张业务表是同一批表的两种计数方式,不是两套结构。
|
2026-09-09 21:55:37 +08:00
|
|
|
|
|
|
|
|
|
|
修改表结构前必须先对照 00 基线。允许新增表和字段,禁止重命名、删除或改变已有字段。结构指纹检查命令:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe tools\schema_fingerprint.py
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 启动 HTTP 服务和 Worker
|
|
|
|
|
|
|
|
|
|
|
|
需要两个终端。
|
|
|
|
|
|
|
|
|
|
|
|
终端一启动 HTTP 服务:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8099
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
终端二启动运行 Worker:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe -m app.worker
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
只处理一轮任务并退出:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe -m app.worker --once
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Worker 的运行参数在 `.env` 中配置:
|
|
|
|
|
|
|
|
|
|
|
|
```dotenv
|
|
|
|
|
|
WORKER_POLL_SECONDS=1
|
|
|
|
|
|
WORKER_LEASE_SECONDS=60
|
|
|
|
|
|
WORKER_RETRY_LIMIT=3
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 服务只负责认证、权限、参数校验和运行受理。模型调用、记忆召回、结果持久化由 Worker 执行。
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 注册业务 Agent
|
|
|
|
|
|
|
|
|
|
|
|
业务 Agent 必须继承 `BaseAgent`,只实现 `AgentDefinition` 和 `handle()`,由 `AgentFactory` 创建。
|
|
|
|
|
|
业务代码不得覆盖 `execute()`、`validate_access()`、`resolve_config()`、`recall_memory()`、`check_compliance()` 或治理绑定方法。
|
|
|
|
|
|
|
|
|
|
|
|
示例:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from app.core.contracts import AgentDefinition, AgentRequest, CoreResult, RequestContext
|
|
|
|
|
|
from app.service.agent.base import BaseAgent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CustomerServiceAgent(BaseAgent):
|
|
|
|
|
|
definition = AgentDefinition(
|
|
|
|
|
|
agent_type="customer_service",
|
|
|
|
|
|
version="1.0.0",
|
|
|
|
|
|
allowed_roles=("customer", "operator", "admin"),
|
|
|
|
|
|
allowed_portals=("api",),
|
|
|
|
|
|
allowed_tools=(),
|
|
|
|
|
|
supported_intents=("general",),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def handle(
|
|
|
|
|
|
self, request: AgentRequest, context: RequestContext
|
|
|
|
|
|
) -> CoreResult:
|
|
|
|
|
|
return CoreResult(text=f"已收到:{request.message}")
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
在 `app/service/agent/bootstrap.py` 的唯一注册入口注册:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from app.service.agent.factory import AgentFactory
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def register_business_agents(factory: AgentFactory) -> None:
|
|
|
|
|
|
factory.register(
|
|
|
|
|
|
CustomerServiceAgent.definition,
|
2026-09-11 14:37:20 +08:00
|
|
|
|
lambda _context: CustomerServiceAgent(CustomerServiceAgent.definition),
|
2026-09-09 21:55:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
然后由 `get_agent_factory()` 在首次创建时调用注册函数。HTTP 服务和 Worker 必须共用这个注册入口,不能各自维护一份注册表。
|
|
|
|
|
|
|
2026-09-11 14:37:20 +08:00
|
|
|
|
当前 `register_business_agents()`(`app/service/agent/bootstrap.py` 约 L210-225)已注册两个业务 Agent:
|
|
|
|
|
|
`FundQueryDemoAgent`(`agent_type="fund_query_demo"`)与 `CustomerServiceAgent`(`agent_type="customer_service"`)。
|
|
|
|
|
|
组员新增 Agent 时在同一个函数里追加一行 `factory.register(...)`。
|
|
|
|
|
|
|
|
|
|
|
|
`agent_type` 使用小写蛇形命名,例如 `customer_service`、`risk`、`advisor`。提交**未注册**的 `agent_type` 会返回 `404 AGENT_TYPE_NOT_FOUND`。
|
2026-09-09 21:55:37 +08:00
|
|
|
|
|
|
|
|
|
|
注册表契约测试会扫描所有已注册 Agent:构造器必须返回 `BaseAgent`,实例定义必须与注册时的
|
|
|
|
|
|
`AgentDefinition` 完全一致。业务 Agent 未通过该契约测试不得合并;工厂创建阶段也会再次拒绝
|
|
|
|
|
|
非法构造器,避免绕过公共执行链。
|
|
|
|
|
|
|
|
|
|
|
|
`get_agent_factory()` 是 HTTP 服务和 Worker 共用的底座组装入口。它会从 `model_endpoint_config`
|
|
|
|
|
|
按端点代码读取激活配置,构造 `DatabaseModelGateway → ModelGenerationService`,并注册公共只读工具
|
|
|
|
|
|
到 `ToolRegistry → ToolExecutor` 后注入工厂。业务组员只需注册自己的 Agent,不得在业务代码中重新
|
|
|
|
|
|
创建模型 Adapter、读取模型密钥或另建工具执行器。
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Agent 的公共执行顺序
|
|
|
|
|
|
|
|
|
|
|
|
每次运行固定经过:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
输入校验
|
|
|
|
|
|
→ 角色、入口和权限校验
|
|
|
|
|
|
→ 读取生效配置
|
|
|
|
|
|
→ 召回当前用户记忆
|
|
|
|
|
|
→ 执行业务 handle()
|
|
|
|
|
|
→ 超时控制
|
|
|
|
|
|
→ 禁止表达、引用、敏感信息和工具记录审查
|
|
|
|
|
|
→ 持久化结果、审计和 Outbox
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
业务 Agent 可读取:
|
|
|
|
|
|
|
|
|
|
|
|
- `self.config`:本次运行的不可变配置快照;
|
|
|
|
|
|
- `self.memories`:当前用户的授权记忆集合;
|
|
|
|
|
|
- `request`:客户端业务输入;
|
|
|
|
|
|
- `context`:服务端生成的身份和权限上下文。
|
|
|
|
|
|
|
|
|
|
|
|
业务 Agent 不得直接创建 SQLAlchemy Session、Redis、Milvus 或 Neo4j Driver。关系查询必须经过 `RelationshipService`,模型调用必须经过模型路由和 `ModelGateway`。
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 提交一次 Agent 运行
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST http://127.0.0.1:8099/api/v1/agent-runs
|
|
|
|
|
|
Authorization: Bearer <JWT>
|
|
|
|
|
|
Idempotency-Key: customer-request-202609090001
|
|
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
请求体:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"agent_type": "customer_service",
|
|
|
|
|
|
"message": "请介绍一下基金风险",
|
|
|
|
|
|
"session_id": "session-uuid",
|
|
|
|
|
|
"idempotency_key": "customer-request-202609090001",
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"locale": "zh-CN",
|
|
|
|
|
|
"client_version": "web-1.0",
|
|
|
|
|
|
"ui_entry": "customer-chat"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
返回 `202`:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"run_id": "run-uuid",
|
|
|
|
|
|
"trace_id": "trace-uuid",
|
|
|
|
|
|
"status": "queued",
|
|
|
|
|
|
"status_url": "/api/v1/agent-runs/run-uuid",
|
|
|
|
|
|
"events_url": "/api/v1/agent-runs/run-uuid/events"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
同一用户、同一 Agent、同一幂等键和同一正文会返回原运行;正文不同会返回 `409 IDEMPOTENCY_CONFLICT`。
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 查询和 SSE 恢复
|
|
|
|
|
|
|
|
|
|
|
|
查询运行:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
GET /api/v1/agent-runs/{run_id}
|
|
|
|
|
|
Authorization: Bearer <JWT>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
订阅 SSE:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
GET /api/v1/agent-runs/{run_id}/events
|
|
|
|
|
|
Authorization: Bearer <JWT>
|
|
|
|
|
|
Accept: text/event-stream
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
运行未完成时只收到 `start` 和心跳;最终事务提交后收到 `tools`(可选)、`delta`、`done`。已完成运行重连时使用 `replace` 返回完整正文。
|
|
|
|
|
|
|
|
|
|
|
|
这是结果级恢复:断线后重新请求同一个 `run_id` 即可恢复,不依赖 Worker 内存,也不实现事件级 `Last-Event-ID` 续传。
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 会话、取消和转人工
|
|
|
|
|
|
|
|
|
|
|
|
创建会话:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/v1/conversations
|
|
|
|
|
|
Idempotency-Key: session-create-202609090001
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{"agent_type": "customer_service"}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
结束会话:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/v1/conversations/{session_id}/closures
|
|
|
|
|
|
Idempotency-Key: session-close-202609090001
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
取消运行:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/v1/agent-runs/{run_id}/cancellations
|
|
|
|
|
|
Idempotency-Key: cancel-202609090001
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{"reason": "user_cancelled"}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
转人工:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/v1/conversations/{session_id}/handover-requests
|
|
|
|
|
|
Idempotency-Key: handover-202609090001
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Agent 只能提出转人工请求,不能直接分配、接单、解决或关闭客服工单。
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 记忆、关系推理和模型路由
|
|
|
|
|
|
|
|
|
|
|
|
记忆提取不提供客户端写接口。`complete_run()` 会在最终事务内写入 `memory.extraction_requested`,由 Outbox Worker 消费。
|
|
|
|
|
|
|
|
|
|
|
|
记忆查询:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
GET /api/v1/users/me/memory-profile
|
|
|
|
|
|
GET /api/v1/customers/{customer_id}/memory-profile
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Neo4j 关系推理必须调用 `RelationshipService`,只能使用白名单关系和受限跳数;Neo4j 不可用时返回降级结果,不得绕过数据权限。
|
|
|
|
|
|
|
|
|
|
|
|
模型调用必须经过:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
ConfigRelease → ModelRouterService → ModelGateway → 主端点/受控 fallback
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
业务 Agent 在 `handle()` 中通过底座注入的 `generate_with_model(endpoints, prompt)` 调用模型,
|
|
|
|
|
|
不得直接导入 `httpx`、供应商 SDK 或自己读取密钥。当前已提供 OpenAI-compatible Adapter;
|
|
|
|
|
|
生产接入时由模型平台根据 `ModelEndpointConfig.base_url`、`model_name` 和 `secret_ref`
|
|
|
|
|
|
构造已批准端点,再交给 `ModelGenerationService`。没有路由端点时会失败关闭并进入 Worker 重试,
|
|
|
|
|
|
不会静默调用环境变量中的默认模型。
|
|
|
|
|
|
|
|
|
|
|
|
意图识别使用公共 `IntentClassifier`,输入为用户消息、Agent 声明的
|
|
|
|
|
|
`supported_intents` 和模型路由结果。模型只能返回严格 JSON;底座会校验意图白名单和
|
|
|
|
|
|
`confidence`(0 到 1),低于发布配置阈值时返回 `needs_clarification=true`,由业务流程澄清,
|
|
|
|
|
|
不得把低置信结果当成确定意图。格式错误、未声明意图和空输入均失败关闭。业务 Agent 不得直连
|
|
|
|
|
|
模型或自行解析供应商响应。
|
|
|
|
|
|
|
|
|
|
|
|
该分类器已经接入 `BaseAgent.execute()`:完成鉴权、配置和记忆召回后,底座会从数据库解析当前
|
|
|
|
|
|
激活模型端点并在 `handle()` 前自动分类,最终分类结果自动写入 `CoreResult.intent`。组员无需调用
|
|
|
|
|
|
`ModelRouterService`、创建 `IntentClassifier` 或向 `handle()` 传端点,也不得覆盖
|
|
|
|
|
|
`classify_intent()` 和 `bind_intent_classifier()`。
|
|
|
|
|
|
|
|
|
|
|
|
工具调用必须经过工厂注入的 `ToolExecutor`。业务 Agent 使用 `await self.call_tool(name,
|
|
|
|
|
|
arguments, intent=..., context=context)`,不能直接访问数据库或外部服务。每个工具必须声明
|
|
|
|
|
|
Pydantic 输入模型、权限码、允许角色和只读属性;公共 Agent 工具拒绝写操作。执行前检查当前
|
|
|
|
|
|
意图白名单、角色、权限和参数,执行过程有超时,结果只保留脱敏摘要,并生成工具来源引用和审计记录。
|
|
|
|
|
|
|
|
|
|
|
|
投顾适当性校验必须使用公共 `SuitabilityService`(或其 `suitability_tool_handler` 工具入口),
|
|
|
|
|
|
不得在业务 Agent 中复制 C1-C5/R1-R5 匹配规则。输入包括客户风险等级、产品风险等级、专业投资者
|
|
|
|
|
|
标记、风险揭示和测评有效期;输出为不可变的 `allowed`、`reason_code`、`required_disclosure`、
|
|
|
|
|
|
`requires_confirmation`、`requires_recording`。客户风险等级低于产品、测评已过期时必须拒绝;专业
|
|
|
|
|
|
投资者也不能绕过审计。通过和拒绝决定都会写入 `interaction_audit`,服务只读,不修改交易、产品或
|
|
|
|
|
|
客户风险资料。业务 Agent 如需校验,应注册只读工具并通过 `self.call_tool(...)` 调用。
|
|
|
|
|
|
|
|
|
|
|
|
接口和日志只保存 `secret_ref`,不保存模型 API 明文密钥。
|
|
|
|
|
|
|
|
|
|
|
|
## 10. 配置管理
|
|
|
|
|
|
|
|
|
|
|
|
管理接口位于 `/api/v1/admin/**`,需要 JWT、管理角色和对应权限。写操作必须同时提供:
|
|
|
|
|
|
|
|
|
|
|
|
- `Idempotency-Key`;
|
|
|
|
|
|
- 更新时的 `If-Match`;
|
|
|
|
|
|
- 合法的发布状态转换。
|
|
|
|
|
|
|
|
|
|
|
|
配置发布流程:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
draft → pending_review → approved → active
|
|
|
|
|
|
↘ rejected
|
|
|
|
|
|
active → superseded / rollback release
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-11 17:26:18 +08:00
|
|
|
|
配置发布的"审核"节点不可跳过(草稿必须先提交审核);单管理员部署下创建人可以审核自己创建的版本,
|
|
|
|
|
|
不再要求复核人必须是另一个身份,`reviewer_id` 如实记录审核人。工具白名单只能缩小代码中
|
|
|
|
|
|
`AgentDefinition.allowed_tools` 的范围,不能通过数据库配置扩大权限。
|
2026-09-09 21:55:37 +08:00
|
|
|
|
|
|
|
|
|
|
## 11. 统一错误处理
|
|
|
|
|
|
|
|
|
|
|
|
常见错误:
|
|
|
|
|
|
|
|
|
|
|
|
| HTTP | 错误码 | 含义 |
|
|
|
|
|
|
|---:|---|---|
|
2026-09-11 16:57:47 +08:00
|
|
|
|
| 422 | `AGENT_INPUT_INVALID` | 请求内容不满足输入约束(含字段校验失败,字段级原因见 `error.field_errors`) |
|
|
|
|
|
|
| 401 | `AUTHENTICATION_REQUIRED` | Token 缺失或无效 |
|
|
|
|
|
|
| 403 | `AGENT_PERMISSION_DENIED` | 角色、入口或数据范围不允许 |
|
|
|
|
|
|
| 404 | `SESSION_NOT_FOUND` / `SESSION_NOT_ACCESSIBLE` / `AGENT_TYPE_NOT_FOUND` / `RUN_NOT_FOUND` | 资源不存在或不可见;非会话资源按同一"资源隐藏"语义复用 `SESSION_NOT_FOUND` |
|
|
|
|
|
|
| 409 | `IDEMPOTENCY_CONFLICT` / `RESOURCE_VERSION_CONFLICT` / `RUN_NOT_CANCELLABLE` / `RUN_CANCELLED` | 幂等、版本或运行状态冲突 |
|
|
|
|
|
|
| 429 | `RATE_LIMITED` | 频率、并发或配额限制 |
|
|
|
|
|
|
| 503 | `DEPENDENCY_UNAVAILABLE` | 必需依赖不可用 |
|
|
|
|
|
|
| 504 | `UPSTREAM_TIMEOUT` | 上游超过时间预算 |
|
|
|
|
|
|
| 500 | `AGENT_INTERNAL_ERROR` | 未分类内部错误 |
|
|
|
|
|
|
|
|
|
|
|
|
> 变更记录(2026-09-11):本表原先使用 `VALIDATION_ERROR`、`UNAUTHORIZED`、`FORBIDDEN`、
|
|
|
|
|
|
> `RESOURCE_NOT_FOUND`、`RECOVERABLE_ERROR` 等未在权威文档中定义的码,已按
|
|
|
|
|
|
> `docs/05-接口文档.md` §3.5 / §3.6 对齐。错误码以 `docs/05-接口文档.md` 为唯一权威源。
|
2026-09-09 21:55:37 +08:00
|
|
|
|
|
|
|
|
|
|
错误响应不会返回 SQL、堆栈、模型原文、供应商响应或密钥。
|
|
|
|
|
|
|
|
|
|
|
|
## 12. 开发完成前的验收命令
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
2026-09-11 14:37:20 +08:00
|
|
|
|
.\.venv\Scripts\python.exe -m pytest -q -p no:cacheprovider
|
|
|
|
|
|
.\.venv\Scripts\python.exe -m ruff check app tests tools alembic
|
|
|
|
|
|
.\.venv\Scripts\python.exe -m mypy app
|
|
|
|
|
|
.\.venv\Scripts\python.exe tools\check_authoritative_docs.py
|
|
|
|
|
|
.\.venv\Scripts\python.exe tools\audit_schema.py
|
2026-09-09 21:55:37 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-11 14:37:20 +08:00
|
|
|
|
当前全量测试基线(2026-09-11 实测):`1 failed, 779 passed, 2 skipped`;唯一失败
|
|
|
|
|
|
`tests/unit/repository/test_fund_readonly_contract.py` 是底座既有缺陷,与本文档所述接入流程无关。
|
|
|
|
|
|
|
2026-09-09 21:55:37 +08:00
|
|
|
|
新增业务 Agent 至少补充:
|
|
|
|
|
|
|
|
|
|
|
|
1. 每个支持意图的正常、低置信和异常用例;
|
|
|
|
|
|
2. 未授权角色、入口、工具和客户范围用例;
|
|
|
|
|
|
3. 配置、记忆、合规、SSE 和最终持久化回归;
|
|
|
|
|
|
4. 业务边界用例,例如 Agent 不得代客下单、审核方案或处置风险预警。
|
|
|
|
|
|
|
|
|
|
|
|
## 13. 当前边界
|
|
|
|
|
|
|
|
|
|
|
|
本底座负责公共架构、鉴权、工厂、运行调度、持久化、记忆基础、关系服务、配置、模型路由和公共接口。
|
|
|
|
|
|
客服、投顾、风控和运营 Agent 的具体意图、提示词、工具实现和业务状态机由业务组员负责,但必须通过本文规定的工厂和公共执行流程接入。
|
|
|
|
|
|
|
|
|
|
|
|
当前系统业务交易范围是场内基金模拟交易。场外运营数据必须使用独立表和独立接口,不得写入场内交易表。
|
2026-09-09 23:40:35 +08:00
|
|
|
|
|
2026-09-11 14:37:20 +08:00
|
|
|
|
## 14. 公共只读工具当前状态
|
2026-09-09 23:40:35 +08:00
|
|
|
|
|
2026-09-11 14:37:20 +08:00
|
|
|
|
`get_agent_factory()` 向 `ToolRegistry` 注册了 **4 个公共只读工具**(`app/service/agent/bootstrap.py` 约 L155-192),
|
|
|
|
|
|
全部经 `ToolRegistry`、`ToolExecutor` 和统一工厂注入,业务 Agent 只能通过 `self.call_tool(...)` 使用:
|
|
|
|
|
|
|
|
|
|
|
|
| 工具名 | 必需权限 | 允许角色 | 只读 | 说明 |
|
|
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
| `check_suitability` | `suitability:read` | customer、advisor、operator、admin | 是 | C1-C5/R1-R5 适当性匹配;测评过期/缺失拒绝;通过和拒绝都写 `interaction_audit` |
|
|
|
|
|
|
| `query_fund_quote` | `fund:quote:read` | customer、advisor、operator、risk_operator、admin | 是 | 场内基金行情;超时 15s;不得改写为成交、委托或持仓语义 |
|
|
|
|
|
|
| `query_knowledge` | `knowledge:query` | customer、operator、advisor、risk_operator、admin | 是 | 知识检索(RAG);集合名由服务端按意图映射;超时 8s |
|
|
|
|
|
|
| `query_customer_profile` | `memory:read:self`(查他人为 `memory:read:customer`) | customer、advisor、operator、risk_operator、admin | 是 | 客户画像白名单投影,不返回 PII;越范围按"不存在"处理 |
|
|
|
|
|
|
|
|
|
|
|
|
**工具白名单是两段式**:代码里的 `AgentDefinition.allowed_tools` 是**上限**;实际可用范围还要与当前
|
|
|
|
|
|
`active` 的 `config_release` 中 `namespace=agent_tools`、`config_key=<agent_type>:<intent>` 发布的工具白名单
|
|
|
|
|
|
**取交集**。缺发布配置时交集为空、工具**失败关闭**;发布配置只能缩小、不能放大代码声明的范围。
|
|
|
|
|
|
|
|
|
|
|
|
以行情工具为例,业务 Agent 必须同时在 `AgentDefinition.allowed_tools` 和发布配置的
|
|
|
|
|
|
`agent_tools/<agent_type>:fund_quote`(`{"allowed_tools": ["query_fund_quote"]}`)中声明后才能使用。
|
|
|
|
|
|
4 个工具的接口面登记口径见《05-接口文档.md》§8.4「公共只读工具索引(Agent 面)」。
|
|
|
|
|
|
未注册业务 Agent 不能直接提交运行,底座也没有开放绕过 Agent 执行链的行情 HTTP 接口。
|