③ 问答
内置工具
引擎随包发布的四个 MCP 工具:术语、健康记录与基因;以及 DeepAgent 从它的 harness 额外获得的能力。
下面每一个工具都是一个普通的 Python 方法,由运行期发现捡起来的。这里没有任何部分被引擎特殊对待,也没有任何一个是编译进去的:找到它们的规则,和找到你写的那个是同一套。
MCP 工具面刻意做得很小。随包一共四个工具,而权威清单永远是你自己那台服务报出来的,直接问它:
curl -X POST http://localhost:18080/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'四个工具分三组提供:术语解析(resolve_indicator、normalize_unit)、健康记录读取(query_health_indicators)与基因数据读取(get_genetic_data)。四个里有两个什么都不需要:不要账号、不要网络、不要 key;另外两个绑定调用者自己的记录:
| 工具 | 做什么 | 需要什么 |
|---|---|---|
resolve_indicator | 任意语言的指标名 → 规范 LOINC | 什么都不需要(离线,不碰用户数据) |
normalize_unit | 自由文本单位 → 规范 UCUM + 可比性族 | 什么都不需要(离线,不碰用户数据) |
query_health_indicators | 调用者自己的记录:检索、读取与聚合在一次调用里完成 | 账号 |
get_genetic_data | 按 rsID 查调用者的变异 | 账号 |
术语 —— ② 标准化的工具面
Section titled “术语 —— ② 标准化的工具面”这两个工具让模型能把一个名字放到与编码同等的位置上。「LDL cholesterol」「低密度脂蛋白胆固醇」和「LDL-C」是同一项测量的三种写法,它们都能被归到同一个规范身份上。两个工具都不读用户数据,所以匿名调用者也能使用,不会泄露任何信息。
解析运行在随包分发的词表上,客户端即便断网也照样答得出来,这正是健康数据应有的性质。
resolve_indicator
Section titled “resolve_indicator” names string[] required
按打印出来的原样传名字。整批一次调用传完。
按输入顺序,每条返回:name 原样、resolved、loinc(例如 718-7,未解析时为空)、canonical(LOINC long common name),以及 candidates:有多少条语料命中。candidates 很大意味着确实存在歧义,而系统挑了一个合理默认;在精度要紧的场合要把这件事讲出来。
有三条性质是明确写给模型看的,因为它们决定了答案该怎么写:
- 未解析是一次诚实的「没有」。 就报告这个名字没匹配上,绝不要编一个编码出来。
- 套餐名刻意不解析。
blood pressure与血圧指的是套餐而不是观测项,正确的反应是反问要哪一项(收缩压还是舒张压)。 - 两个名字获得同一个编码,就是同一项检查。 决定两条读数能不能比较的是这个,而不是字符串相等。
normalize_unit
Section titled “normalize_unit” units string[] required
按打印出来的原样传单位串,例如 ["mg/dL", "毫摩尔每升", "次/分"]。单次最多 200 个。
返回 unit 原样、ucum(规范形式;为空表示没认出来)与 family(也就是 LOINC PROPERTY,例如 SCnc)。
- "MG/DL"
- ucum "mg/dL" · family "MCnc"
- "毫摩尔每升"
- ucum "mmol/L" · family "SCnc"
族才是重点:同一族内的单位可以互换,跨族换算是范畴错误,不是算术。
query_health_indicators
Section titled “query_health_indicators”该工具将检索、读取与聚合合并为单次调用,而且每条结果都带着它的规范身份。
keywords string[]
模糊词,任意语言。缩写请把两种写法都给上,例如 ["MCHC", "Mean Corpuscular Hemoglobin Concentration"]。
indicators string[]
上一次调用返回的精确名字。用它替代 keywords,而不是和猜的词混着用。
start_time string
起始日期(含),YYYY-MM-DD。
end_time string
结束日期(含),YYYY-MM-DD。
aggregate string default: none
取 none、stats、day、week、month 之一:它在 schema 里被声明成 enum,所以非法取值在引擎代码运行之前就会被拒。stats 按指标返回 count/min/max/avg/first/last/change;给一个时间桶则每桶返回一个点。趋势类问题应该用它们,而不是把原始读数全拉下来。
limit integer default: 50
aggregate 为 none 时,每个指标最多返回多少条读数。上限 500 写在 schema 本身里。
返回结构是按「让模型不用靠猜就能继续」来设计的:
| 字段 | 是什么 |
|---|---|
indicators | 每个命中项:indicator(精确名字,可以直接回填给 indicators)、system / code(规范身份:编码相同就是同一项检查,不管名字怎么写)、count,以及 rows(竖线分隔的表格)。开头那行 (constants: k=v) 装的是每行都相同的列,通常就是单位。 |
catalog | 在没给任何过滤条件时、以及什么都没匹配上时,代替 indicators 返回:列出这个用户实际有什么,好让模型从现实里挑,而不是重新猜关键词。 |
truncated | 指标 → 实际总量,当某个序列被 limit 截断时出现。正确的处理是缩窄时间窗或改用聚合,而不是把 limit 调大。 |
get_genetic_data
Section titled “get_genetic_data” rsid string | string[] required
dbSNP 标识符,例如 "rs4988235" 或 ["rs1801133", "rs429358"]。逗号分隔的字符串也行。
limit integer default: 100
最多返回多少个变异。
include_nearby boolean default: true
同时返回每个命中点 nearby_range 范围内的变异,每个命中最多 20 个。只要精确查询就设 false。
nearby_range integer default: 1000000
半窗宽度,单位是碱基对。
它读的是用户自己上传的基因型文件,不是参考数据库。消费级芯片只检测基因组的一小部分,所以没有 ≠ 阴性:结果里缺了某个 rsID,只说明它没被检测,对等位基因什么都没说。
DeepAgent 从 harness 获得的额外工具
Section titled “DeepAgent 从 harness 获得的额外工具”上面那张表对 DeepAgent 而言并不是全部:它的 deepagents harness 还会额外提供一些能力,而那些不是 MCP 工具,外部 MCP 客户端看不到它们。
| 来自骨架 | 是什么 |
|---|---|
ls · read_file · write_file · edit_file · glob · grep | 原生文件工具,作用在由 PostgreSQL 支撑的虚拟文件系统上。对着上传的 PDF 调 read_file,交给模型的是原始文档本身(多模态),而不是一份有损的抽取结果。 |
eval | 来自 langchain-quickjs 的持久进程内 JavaScript REPL,模型就是靠它对取来的数据做真正的计算。 |
| Agent Skills | 不是工具:SKILL.md 写的流程,以 frontmatter 注入,只在任务需要时才读全文。见 Agent Skills。 |
delete 被按名字排除:PostgreSQL 文件系统后端没有实现它。没有 task 子代理,也没有 write_todos。