lzf_0626
|
1eb8946552
|
test(base): 端到端验证工具拒绝的分支 2 与 3,探针加第二个工具
接上一轮(分支 1 已验证)。本轮用只读探针触发另外两种拒绝:
- 分支 2「工具不在当前意图白名单」:发布白名单 ["probe_alt"] 但 Agent 调 probe_echo。
这一步能做,正是因为给探针加了第二个工具 —— governance.resolve 取的是
「发布白名单 ∩ 代码声明的 allowed_tools」,配置**只能缩小不能放大**,所以单个工具的
Agent 永远构造不出"有白名单但不含该工具"的场景。这是做端到端时才撞到的结构性约束,
platform_probe.py 里已注明。
- 分支 3「缺少工具权限」:发布白名单 ["probe_echo"],工具可用了,但 admin 角色并没有
probe:read 这条权限,天然命中权限分支,不需要动 RBAC。
实测:两种拒绝的 stderr 分别为「工具不在当前意图白名单」与「缺少工具权限」,
运行状态均为 failed / AGENT_PERMISSION_DENIED;生效配置已恢复(终点 9 条,与起点一致)。
顺带发现分支 4 的结构性障碍(下一步处理):Agent 层的 validate_access 会先按
AgentDefinition.allowed_roles 拦截,所以要在**工具层**触发"角色不能使用工具",
必须让工具的角色集合比 Agent 的更窄 —— 探针目前两者的角色集合相同,触发不到。
|
2026-09-11 13:11:30 +08:00 |
|
lzf_0626
|
edc0c43245
|
test(base): 造只读探针端到端验证工具拒绝,并修掉它暴露的一个死分支
**为什么造探针**:ToolExecutor 的四种拒绝在真实链路上很难安全触发——要么改客服、风控的
生效配置,要么动 RBAC,两条路都会影响正在工作的 Agent。platform_probe 是个只读、无副作用
的探针:它只声明 probe 一个意图(所以意图分类只可能返回它)、没有发布工具白名单
(天然处于"未配置"状态)、工具只回显参数不碰业务数据。
**它立刻查出一个死分支**:探针报的是「工具不在当前意图白名单」,而不是我新加的
「该意图未配置工具白名单」。原因是 governance.resolve 会为每个 supported_intents
**预填条目**(governance.py:55-61),未配置时得到的是**空元组**——所以
intent not in configured_tools 在运行期**永远不成立**,那个分支是死代码。
单元测试没能发现它,因为我在测试里手工构造了 configured={},而真实链路不产生这个形状。
**这正是端到端测试的价值**:单元测试验证的是我设想的形状,端到端验证的是真实形状。
修法:改判"白名单为空"而非"缺键",文案改为"该意图的工具白名单为空",并注明经过 governance
装配后"完全没配"与"配了空列表"无法区分、也不假装能区分(两者运维动作相同)。新增一条按
**真实形状**({"faq": ()})构造的用例把它锁住。
实测:探针调用 → failed / AGENT_PERMISSION_DENIED,stderr 为
ForbiddenAgentError: 该意图未配置工具白名单(tool_executor.py:108)。
ruff / mypy(136 文件) / 611 unit+contract 全绿。
|
2026-09-11 13:10:04 +08:00 |
|
lzf_0626
|
478b64e4d7
|
Merge remote-tracking branch 'origin/qyqy_develop' into qyqy_develop_1
# Conflicts:
# app/service/agent/bootstrap.py
|
2026-09-11 10:43:08 +08:00 |
|
lzf_0626
|
75dff088d4
|
feat: 接通 Neo4j 图能力(驱动实现 + 装配),并实测确认图模型标签不一致
第 2 步(图库)的地基部分。
1. 新增 app/infrastructure/graph.py:GraphDriver 协议的 neo4j 实现。
这层此前是空的——relationship_service.py 里的 GraphDriver 只有 Protocol 声明、没有任何
具体实现,组装层也没有装配它,因此图读服务在运行期必然降级(neo4j_unavailable)。
这正是"Neo4j 连读适配器都没有"的根因。
降级取向与 Milvus 侧一致:本层不吞异常(由调用方决定降级方式),但构造失败返回 None
——图库不可用不该让应用起不来,也不该阻塞主链路。
2. bootstrap 新增 get_relationship_service():装配图读服务。
该服务只读,关系类型受 ALLOWED_RELATIONSHIPS 白名单约束;写入走 GraphProjectionWorker
(由领域事件驱动),这里不提供任意写接口——避免出现绕过事件链路的直写路径。
3. 实测确认一处既有缺陷(本次不改,方案待定):投影 worker 写入的节点标签是
:Entity {entity_id}(字符串属性),而 RelationshipService.neighbors 查询的是
:Customer {customer_id}(整数属性),两侧从未对齐,写进去的关系读不出来。
Neo4j 在执行读查询时直接给出三条警告佐证:未知标签 Customer、未知属性 customer_id、
未知关系类型 PREFERS——这也说明业务图从未被真正投影过(库中只有 Neo4j 自带的
Person/Movie 示例数据,共 5 个节点)。
验证:ruff 通过、mypy 110 文件无错;get_relationship_service() 返回 RelationshipService,
neighbors 与 paths 正常执行并返回空集(非降级),非法关系类型被白名单拒绝。
|
2026-09-10 21:40:00 +08:00 |
|
zhangshy
|
a94d5c754d
|
feat: 迁移奶龙风控业务模块与演示文档
|
2026-09-10 21:03:44 +08:00 |
|
lzf_0626
|
13bab7c3d0
|
feat: 客服 Agent 端到端跑通(知识直返 + 答不了引导人工客服)
按业务方确定的取向实现:金融场景确定性优先,能溯源到公司资料的才答,答不了就
引导客户拨打客服热线,绝不用模型猜答案。端到端验收 8/8 通过。
新增:
- app/service/knowledge_search_service.py:知识检索。未复用记忆的 VectorMemoryAdapter
是因为它只返回 (memory_uuid, score),会丢掉知识块的标题与正文,而客服回答必须能把
原文与出处一起交付。检索失败一律返回 degraded 而不抛异常,由 Agent 走兜底。
- app/service/knowledge_tool.py + app/core/knowledge_contracts.py:只读工具 search_knowledge。
走 ToolExecutor 而不是让 Agent 直接持有检索服务,是为了让白名单、权限、审计、超时
都归基座统一管理;工具只读也符合 ToolRegistry 的硬约束。复用既有权限码
knowledge:reference:read(customer 角色已具备),不新增权限点。
- app/service/agent/implementations/customer_service.py:Agent 本体,刻意保持薄——
意图分发 + 四条出口(faq/产品/政策直返、闲聊走模型、其余与异常引导人工)。
直接返回知识原文而不经模型改写,答案的字面内容全部来自公司已发布资料。
- tools/publish_customer_service_config.py:发布意图工具白名单。
- tools/customer_service_check.py:端到端验收(8 个用例,含越界请求与知识库外问题)。
装配:
- bootstrap 新增 get_knowledge_search_service 工厂,注册 search_knowledge 工具与
customer_service Agent。
- runtime_config_service 新增 load_active_prompt:提示词绑定 release_id,按当前生效
版本读取,未发布时回落代码默认值。闲聊话术因此可审核、可回滚,不必改代码发版。
过程中发现并处理的三个问题:
1. 自造 source_references 被基座合规闸门拒绝。governance.review_output 只接受
「本次召回的记忆」与「本次成功调用的工具」两类引用(用于防止伪造来源),
knowledge 类型会被判非法并使整个 run 失败。处理方式是**不放开那道校验**,
而把知识出处(文件标题与内部编号)写进正文,source_references 交给基座自动附加。
2. 发布配置是整版本替换语义:新版本会清空旧版本的全部配置项。若只发客服白名单,
示例 Agent 的 fund_query_demo:fund_quote 会被静默清空。故发布脚本先读取当前生效
版本的全部配置项并原样继承,再追加新增项。
3. 验收脚本自身两处自伤:打印 emoji 触发 GBK UnicodeEncodeError、以及读错结果字段
(RunQueryService 返回的答案键是 content 不是 text)。
已知缺口(未修,已记录):
- CoreResult.transfer_required 未持久化:conversation_message 不存该标记,
API 读不到"本次是否引导了人工"。当前靠正文里的固定话术判断。
- 知识块引用(source_type=knowledge)尚未启用,需先让 ToolExecutor 把工具返回的
doc_id 登记为本次可引用来源。
验证:ruff 通过、mypy 107 文件无错、unit+contract 447 passed;
tools/customer_service_check.py 8/8 通过(含越界请求、投诉、知识库外问题三类
必须引导人工的场景,以及 7 个零容忍负面词零命中)。
|
2026-09-10 20:22:42 +08:00 |
|
lzf_0626
|
6516ccb385
|
feat: 第二版——接口契约对齐 docs/05,修复静默故障与数据库基线
相对第一版 46fc976 的完整变更。组员迁移对照表见 docs/20。
一、对外契约对齐 docs/05(破坏性,共 4 处,组员需按 docs/20 调整)
1) 配置发布端点改为文档规定的复数资源名:submit→validations、
approve→reviews(需 body decision)、activate→activations、
rollback→rollbacks;第一版这 4 个动词式路径 docs/05 从未定义过。
2) 错误码由 8 个笼统码改为 15 个具体语义码(FORBIDDEN→AGENT_PERMISSION_DENIED、
UNAUTHORIZED→AUTHENTICATION_REQUIRED、CONFLICT→RESOURCE_VERSION_CONFLICT、
RESOURCE_NOT_FOUND→RUN_NOT_FOUND/SESSION_NOT_FOUND 等),
输入类错误状态码 400→422。
3) POST /api/v1/agent-runs 与 GET /api/v1/agent-runs/{run_id} 统一为
{data, meta} 信封(data 内字段名与语义未变)。
4) 错误响应体统一为 {error:{code,message,retryable,field_errors}, meta:{trace_id}},
不再返回 FastAPI 默认的 {"detail": ...}。
二、数据库基线与约束
新增 39 张表的基线迁移(链根)与联合唯一键纠偏(4 张表、删 8 增 4,幂等收敛);
撤下 config_release 的双人复核 CHECK(应用层已允许自审,审核节点保留,
自审如实写入 reviewer_id);记忆 active key 生成列与唯一键;
activate 开始记录 supersedes_release_id 使版本链可追溯。
docs/00 基线未修改,未重命名或删除任何表与字段。
三、修复会静默出错或无报错的缺陷
- 跑完集成测试后平台会静默失去生效配置:清理只删自己创建的版本,却没有恢复被它
顶成 superseded 的原生效版本,且审计一并删除因而完全无痕,表现为所有工具被拒
但没有任何报错。已修清理逻辑并加恢复。
- Worker 单轮异常导致进程退出;记忆抽取调用方的“事务已开始”异常;
召回缓存丢失 degraded 标记;连接时区未生效导致 created_at/updated_at 差 8 小时;
.env 与 os.getenv 密钥来源分裂导致“没有可用的已批准模型端点”。
- 记忆信号识别漏判与跨键误命中;SSE 未带 Accept 的协商行为。
四、功能补齐
记忆链路 P1/P2/P3(抽取、受控词表、召回与缓存、生命周期级联及投影事件)、
fin_* 场内交易只读 ORM 层、agent_intent_config 状态流转并在运行期真正生效、
限流(Redis 固定窗口、故障一律放行)、游标校验、trace_id 中间件、
示例业务 Agent fund_query_demo 与一键端到端验证脚本,以及审计/指纹/迁移状态工具。
五、文档与验证
新增 docs/19(业务 Agent 接入实操)、docs/20(第一版迁移指南)与 docs/evidence 证据;
docs/01/02/06/08/09/17 同步实现现状。
验证结果:ruff 通过、mypy 103 文件无错、unit+contract 447 passed、
integration 29 passed、acceptance_check --production 7 PASS、
demo_agent_e2e 9/9 PASS(含失败关闭反证)。
|
2026-09-10 15:55:54 +08:00 |
|
lzf_0626
|
46fc976b24
|
feat: add shared fund quote capability
|
2026-09-09 23:40:35 +08:00 |
|
Codex
|
b1497fd2c6
|
chore: initialize project repository
|
2026-09-09 21:55:37 +08:00 |
|