Files
group_fqcd_jr/docs/09-底座使用文档.md

392 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 奶龙基金 Agent 底座使用文档
> 版本:v1.0
> 适用范围:底座负责人、业务 Agent 开发人员、接口联调人员
> 当前运行方式:FastAPI + MySQL + 独立 Worker + Redis/Milvus/Neo4j 可选基础设施
本文说明如何启动底座、注册业务 Agent、提交运行、读取结果,以及如何使用记忆、配置、模型路由和公共会话能力。
接口字段的最终权威定义仍是《05-接口文档.md》,数据库的最终权威定义仍是《00-新数据库基线设计.md》和《02-数据库建表设计.md》。
## 1. 运行前提
项目固定使用 Python 3.13 环境:
```powershell
conda activate jr_py313
python --version
```
首次安装依赖:
```powershell
pip install -r requirements.txt
```
项目依赖的 `.env` 不提交到代码仓库。可以复制模板后填写本机配置:
```powershell
Copy-Item .env.example .env
```
至少需要配置:
```dotenv
JWT_ISSUER=jr-local
JWT_AUDIENCE=jr-agent-platform
APP_NAME=奶龙基金
JWT_PUBLIC_KEY_PATH=config/jwt/jwt-public.pem
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
alembic upgrade head
python tools/audit_schema.py
```
当前数据库包含 51 张表,其中包括:
- 原有 49 张基线和已落地表;
- `svc_conversation_session` 会话表;
- `api_request_receipt` 公共 HTTP 写操作幂等回执表。
修改表结构前必须先对照 00 基线。允许新增表和字段,禁止重命名、删除或改变已有字段。结构指纹检查命令:
```powershell
python tools/schema_fingerprint.py
```
## 3. 启动 HTTP 服务和 Worker
需要两个终端。
终端一启动 HTTP 服务:
```powershell
conda activate jr_py313
python -m uvicorn app.main:app --host 127.0.0.1 --port 8099
```
终端二启动运行 Worker:
```powershell
conda activate jr_py313
python -m app.worker
```
只处理一轮任务并退出:
```powershell
python -m app.worker --once
```
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,
lambda context: CustomerServiceAgent(CustomerServiceAgent.definition),
)
```
然后由 `get_agent_factory()` 在首次创建时调用注册函数。HTTP 服务和 Worker 必须共用这个注册入口,不能各自维护一份注册表。
`agent_type` 使用小写蛇形命名,例如 `customer_service`、`risk`、`advisor`。如果没有注册业务 Agent,提交该类型会返回 `404 AGENT_TYPE_NOT_FOUND`。
注册表契约测试会扫描所有已注册 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
```
创建人不能审核自己的配置。工具白名单只能缩小代码中 `AgentDefinition.allowed_tools` 的范围,不能通过数据库配置扩大权限。
## 11. 统一错误处理
常见错误:
| HTTP | 错误码 | 含义 |
|---:|---|---|
| 400/422 | `VALIDATION_ERROR` | 请求字段或业务输入不合法 |
| 401 | `UNAUTHORIZED` | Token 缺失、无效、过期或身份字段非法 |
| 403 | `FORBIDDEN` | 角色、权限、入口或数据范围不允许 |
| 404 | `AGENT_TYPE_NOT_FOUND` / `RESOURCE_NOT_FOUND` | Agent 或资源不存在/不可见 |
| 409 | `IDEMPOTENCY_CONFLICT` | 同一幂等键对应不同请求 |
| 503 | `RECOVERABLE_ERROR` | 可重试依赖或执行错误 |
错误响应不会返回 SQL、堆栈、模型原文、供应商响应或密钥。
## 12. 开发完成前的验收命令
```powershell
python -m pytest -q -p no:cacheprovider
python -m ruff check app tests tools alembic
python -m mypy app
python tools/check_authoritative_docs.py
python tools/audit_schema.py
```
新增业务 Agent 至少补充:
1. 每个支持意图的正常、低置信和异常用例;
2. 未授权角色、入口、工具和客户范围用例;
3. 配置、记忆、合规、SSE 和最终持久化回归;
4. 业务边界用例,例如 Agent 不得代客下单、审核方案或处置风险预警。
## 13. 当前边界
本底座负责公共架构、鉴权、工厂、运行调度、持久化、记忆基础、关系服务、配置、模型路由和公共接口。
客服、投顾、风控和运营 Agent 的具体意图、提示词、工具实现和业务状态机由业务组员负责,但必须通过本文规定的工厂和公共执行流程接入。
当前系统业务交易范围是场内基金模拟交易。场外运营数据必须使用独立表和独立接口,不得写入场内交易表。
## 14. 基金行情工具当前状态
底座已注册 `query_fund_quote` 公共只读工具,经过 `ToolRegistry`、`ToolExecutor` 和统一工厂注入。
业务 Agent 必须同时在 `AgentDefinition.allowed_tools` 和发布配置的
`agent_tools/<agent_type>:fund_quote` 中声明后才能使用。未注册业务 Agent 不能直接提交运行,
底座也没有开放绕过 Agent 执行链的行情 HTTP 接口。