内容
管弦
**基于来源,安全回答,控制的LLM代理环境。**
在服务中添加LLM时,最重要的是什么? **流畅的错误答案比可靠的答案更重要,有时需要。** 没有根据的漂亮句子可能会导致事故。
通常的单个代理由一个模型判断,调用工具并编写答案。 然后我们只能希望它不会捏 Orchestrion颠覆了这种结构。 顺序由代码决定,模型在每个阶段只做出自己的判断。 因此,所有答案都经过输入网关, 每个句子都有依据,并经过输出验证屏幕。
Claude Code和几个依赖项就绪后,可以立即运行。 受控的代理路由,防护栏,基于知识库(KB)的响应绑定在一个场景中。 屏幕显示韩语,示例为化学安全文档,但引擎不限于领域,可以应用于文档集。
![Orchestrion流程仪表盘 — 问题通过节点图,引用[S#]·[DB#]依据并经过输出验证](docs/dashboard.jpg)
> 一个问题经过输入网关 → 计划 → 依据收集 → 审查 → 输出验证6个> 所有答案的事实句子都链接到文档块([S#])和格式化事实([DB#])。
> 右侧面板实时显示执行的SQL,查询的事实表,工具调用和防护栏判决。
---
## 核心原则
- **指挥由桥梁而非模型负责。** 每个节点只调用一个LLM(网关 → 路由 → 计划 → 工作审查 → 验证)。 下一个节点由Python桥梁根据规则决定,而不是模型。 控制流程在长对话中不会偶然决定遵循和可复制- **依据验证后才通过。** 工作节点为每个事实句子提供依据 —
来自文档则为[S#],来自格式化数据则为[DB#]。 如果没有依据,不会捏造答案,而是明确表示 **"资料中无"**。 然后,由单独的验证节点将草稿与依据进行二次核对。
- **工具网关唯一且必经。** 所有工具调用都经过一个策略钩子。 此钩子在每次调用规则存储时都会重新读取,因此在屏幕或自然语言中启用或禁用规则会立即生效。
- **任何环节都不会无声无息地崩溃。** 如果没有嵌入模型,搜索将仅使用BM25;如果完全没有知识,图仍会运行并诚实地回答不知道。 在任何环节都不会无声无息地崩溃。
- **身份由内容而非代码定义。** 一个代理由`scenario.md` + `knowledge/raw/` + `data/demo.json` + 防护栏策略每次执行时重新读取这些文件。 因此,创建新业务不是重新编写引擎,而是更换内容。
---
## 架构
### 执行流程
一个问题通过此节点图。 **桥梁根据规则决定分支和顺序,** 每个节点只调用一个模型做出自己的判断。
```mermaid
flowchart LR
Q([问题]) --> RMI["输入网关<br/>rm_input"]
RMI -. REJECT .-> DECL([礼貌拒绝])
RMI -- ALLOW --> RT<br/>route"}
RT -- 简单 --> SA["即/>simple_answer"]
RT -- 业务 --> PL["计划<br/>plan"]
PL --> WK["依据收集·初稿<br/>worker"]
WK --> RV["审查<br/>review RV -. "REDO ≤ 2" .-> WK RV --> RMO["输出验证<br/>rm_output"]
SA --> RMO
RMO --> ANS([验证通过的答案])
classDef rm fill:#fde2e2,stroke:#c0392b,color:#7b241c;
classDef hyp fill:#e2ecfd,stroke:#2c5aa0,color:#1a3c6e;
classDef wrk fill:#e6f6ea,stroke:#27ae60,color:#186a3b;
class RMI,RMO rm;
class RT,SA,PL,RV hyp;
class WK wrk;
```
### 节点 — 什么,由哪个模型
| 节点 | 轨道 | 角色 | 模型 |
|---|---|---|---|
| `rm_input` | 风险管理 | 判断问题是否在业务范围内 — 若不在,则礼貌拒绝 | haiku |
| `route` | 总控 | 分支:是简单问题(即答)还是实际业务 | haiku |
| `simple_answer` | 总控 | 对简单问题(如问候)作出简短即答 | sonnet |
| `plan` | 总控 | 根据`业务方式`流程规划搜索计划 | sonnet |
| `worker` | 使用知识工具收集依据,撰写引用[S#] / [DB#]的初稿 | sonnet |
| `review` | 总控 | 审查初稿是否回答问题并具备依据 — 若不足,则重试(最多2次) | haiku |
| `rm_output` | 风险管理 | 将与依据对照,和语气,输出JSON判决 | haiku |
三个**轨道**(`风险管理` / `总控` / `业务`)在仪表盘上用颜色区分, 便于查看当前节点的性质。
### 验证合约 — [S#] 和 [DB#]
本项目最用心之处。 工作节点可以引用的依据只有两种。
- **`[S#]`** — 从文档中剪切的区块。 由混合搜索找到的原文,在屏幕上显示为橙色。
- **`[DB#]`** — 格式化事实表的一行。 通过SQL查询精确数值或属性,显示黄色,并附带执行的查询和结果表。
没有依据的句子不能写出,否则会回答 **"资料中无"**。 最后,`rm_output`节点会将初稿的事实句子与依据再次核对,只有通过验证的答案才会传递给用户。
### 知识管道
```
knowledge/raw/*.md
│ ingest (make ingest)
▼
区块分割 ─→ FTS5索引(BM25)+ 嵌入(bge-m3)+ LLM事实提取
▼
SQLite(docs · chunks · chunks_fts · embeddings · facts)
▲
│ 只有worker的4个只读工具可以访问(MCP)
│ search_knowledge · read_doc · query_facts · list_sources
```
搜索结合BM25和余弦相似度,使用互惠秩融合(RRF)。 如果没有嵌入模型,则自动仅使用BM25,确保在任何环境下演示都不会停止。
### 组件
| 文件 | 角色 |
|---|---|
| `bridge/graph.py` | 节点图 + 模型层暖会话池(在运行间保持,节点间使用新会话ID隔离历史) |
| `bridge/hooks.py` · `bridge/policy.py` | 唯一的工具网关 + 可编辑的首匹配规则存储库 |
| `bridge/api.py` · `bridge/app.py` | REST API + WebSocket事件馈送,静态前端服务 |
| `bridge/scenario.py` | 解析`scenario.md`,在运行时将图提示注入 |
| `core/db.py` · `core/search.py` · `core/embed.py` | SQLite模式 · 混合搜索 · 嵌入(降级支持) |
| `ingest/` | Markdown → 区块 → FTS → 嵌入 → 事实加载 |
| `mcpserver/server.py` | FastMCP — 向worker暴露的4种知识工具 |
| `frontend/` | 实时显示图表的React仪表盘 |
每个组件的详细说明和不变式(invariant)见 [`CLAUDE.md`](./CLAUDE.md)。
---
## 快速开始
准备事项: [uv](https://docs.astral.sh/uv/)(Python 3.11),Node 18+,Claude订阅或API密钥,若使用嵌入,则需要[ollama](https://ollama.com/) + `bge-m3`(可选)。
```bash
cp .env.example .env # 可选:设置ANTHROPIC_API_KEY,否则使用订阅认证
make setup # uv sync
make ingest # knowledge/raw/ → kb.sqlite
./start.sh # FastMCP + 桥梁,前端构建,自动打开浏览器
```
### 访问界面
`./start.sh`会构建前端并启动桥梁和前端。 因此,可以在浏览器中访问**http://localhost:8787**,进入仪表盘(自动打开,若不需要,可使用 `./start.sh --no-open`)。 顶部选项卡可切换三个界面。
| 界面 | 显示内容 |
|---|---|
| **流程** | 输入问题,节点图实时显示,引用依据和验证判决 |
| **知识体系** | 浏览已加载文档、区块、事实,并进行混合搜索 |
| **防护栏** | 启用或禁用工具策略规则,查看已允许或阻止的日志 |
单独操作前端时,使用带有HMR的开发服务器更方便。 使用 `./start.sh --dev` 启动Vite,**http://localhost:5173** 将显示,`/ws`将被代理到桥梁。
在仪表盘中输入问题,可以看到图正在运行。 如果不需要界面,可以:
```bash
python scripts/graph_probe.py "物质A的1日最大处理量和燃点是多少?"
curl -s localhost:8787/api/kb/stats
```
## 用自己的知识替换
1. 在`knowledge/raw/`中添加整理好的`.md`文件。 (未包含PDF解析器,请先转换为Markdown。)
2. 重写`scenario.md`(摘要/目标/禁止 + `业务方式:`项目)。 此内容将在执行时作为图提示。
3. 运行`make ingest`后重启。
生成的bundles可以保存为`scenarios/<名称>/`下的快照,需要时可以替换。 默认的`scenarios/chemical/`是一个示例。
## 许可证
MIT — 参见 [LICENSE](./LICENSE)。