LLM编排师
本地LLM编排器使用FastAPI构建,由Gemma 4 26B(MoE,4B活动参数,Q4_K_M)通过Ollama提供支持。具有本地工具调用、内置推理和MCP工具服务器,用于通过UDP进行实时NASA SUITS TSS2026遥测、参考文档搜索(文本+PDF)和通过base64图像注入进行直接视觉分析。
快速开始
# Install dependencies (requires Python 3.12+)
uv sync
# Pull required Ollama models
ollama pull gemma4:26b # Chat model (~17GB)
ollama pull qwen3-embedding:0.6b # Embedding model (needed if RAG is re-enabled)
# Configure TSS server connection (set to the IP/port of the running TSS instance)
# Edit .env:
# TSS_UDP_HOST=
# TSS_UDP_PORT=14141
# Run the orchestrator
uv run python main.py编排器开始 http://0.0.0.0:13853.
端点
| 方法 | 路径 | 描述 |
|---|---|---|
| 职位 | /chat | 与MCP工具调用和推理的代理聊天 |
| 得到 | /context | 上次令牌使用情况明细 /chat 呼叫 |
| 得到 | /health | LLM后端连接、模型可用性、MCP工具数量 |
POST/聊天
// Request
{
"messages": [
{"role": "user", "content": "What is the EVA1 oxygen status?"}
],
"stream": false
}
// Response
{
"role": "assistant",
"content": "EVA1: O2 94%, CO2 0.5%, HR 72 bpm, suit pressure nominal."
}该模型使用Gemma 4的原生思维来推理请求,然后自主调用MCP工具(例如,通过UDP获取实时TSS遥测数据,搜索参考文档)。思维跟踪记录在服务器端,但从未流式传输到客户端。
配置
所有设置都是从环境变量中读取的(默认情况下)。创建一个 .env 要覆盖的项目根目录中的文件:
# LLM provider: "ollama" (default), "afm", "llamacpp"
LLM_PROVIDER=ollama
LLM_MODEL=gemma4:26b
LLM_API_BASE= # auto-set per provider if empty
# Ollama host -- always localhost. If OLLAMA_HOST is set system-wide to 0.0.0.0
# (Ollama's server bind address), the orchestrator automatically remaps it to localhost.
OLLAMA_HOST=http://localhost:11434
# Tokenizer -- auto-selected per provider if not set
# TOKENIZER_NAME=google/gemma-4-26B-A4B-it
# Context management
MAX_CONTEXT_TOKENS=128000
SUMMARIZE_THRESHOLD=80000
# TSS2026 server (UDP telemetry -- used by the get_tss_state MCP tool)
# Set TSS_UDP_HOST to the IP of the running TSS instance.
TSS_UDP_HOST=10.206.64.189
TSS_UDP_PORT=14141
TSS_UDP_TIMEOUT=2.0提供程序默认值
| 提供程序 | 默认API基础 | 默认模型 | 默认标记器 | 注释 |
|---|---|---|---|---|
ollama | http://localhost:11434 | gemma4:26b | google/gemma-4-26B-A4B-it | 完整的Ollama SDK,原生思维+工具 |
afm | http://localhost:9999 | mlx-community/Qwen3.5-35B-A3B-4bit | Qwen/Qwen3-35B-A3B | OpenAI兼容(AFM/MLX) |
llamacpp | http://localhost:8080 | gemma4 | google/gemma-4-26B-A4B-it | OpenAI兼容(火焰服务器) |
建筑
orchestrator/
main.py FastAPI app, /chat agentic loop
config.py All configuration, env var loading, MCP server wiring
llm_provider.py Provider abstraction: Ollama, AFM/MLX, llama.cpp
tss_udp_client.py Async UDP client for TSS2026 telemetry
mcp_client.py MCP server lifecycle, tool discovery, tool execution
context_manager.py Token counting, budget calculation, truncation
context_summarizer.py Auto-summarizes when conversation exceeds 80k tokens
docs/ Reference documents searchable by the LLM (text, PDF, images)
mcp_servers/
tss_tools_server.py MCP server: get_tss_state, search_docs, read_doc, inspect_image
rag_service.py Conversation history via LanceDB (disabled, preserved for later)
test_tss_udp.py Smoke test for UDP connectivity to TSS2026主动MCP工具
| 工具 | 描述 | 最大输出 |
|---|---|---|
get_tss_state | 通过UDP获取实时TSS2026遥测数据。范围: all, eva, rover, ltv, ltv_errors, vitals. | 4K字符 |
search_docs | 为文本模式选择docs/。搜索文本文件和PDF。返回file:line:match,没有周围的上下文。 | 50场比赛 |
read_doc | 阅读文档或章节。使用after search_docs展开特定行周围的上下文。 | 2K默认值,8K最大值 |
inspect_image | 通过base64注入将docs/中的图像直接加载到LLM的视觉上下文中。主LLM看到图像本身(不是二手描述)。地图、图表、设备照片。 | 每张图片约3-5K视觉标记 |
LLM根据用户的提示决定何时调用这些工具。没有自动注入,也没有后台轮询。
禁用工具(保留以备后用)
| 工具 | 说明 | 如何重新启用 |
|---|---|---|
search_knowledge | 通过LanceDB嵌入对过去对话进行语义搜索 | 取消注释 tss_tools_server.py 和 main.py |
TSS2026集成
这 get_tss_state MCP工具通过UDP(端口14141)直接与NASA SUITS TSS2026服务器通信。TSS服务器是由NASA管理的外部依赖项,编排器只需要其IP地址和端口即可连接。
TSS协议使用大端二进制数据包:客户端发送8字节的请求([uint32 timestamp][uint32 command])并接收JSON遥测作为响应。
| 命令 | 作用域 | 返回数据 |
|---|---|---|
| 0 | rover | 加压漫游车遥测(位置、转向、激光雷达、驾驶室、电池) |
| 1 | eva | EVA1/EVA2套件遥测、DCU、UIA、IMU、错误 |
| 2 | ltv | LTV最后已知位置、信号强度 |
| 3 | ltv_errors | LTV错误程序 |
| -- | vitals | 过滤后的EVA数据:心率、氧气、二氧化碳、温度、仅电池 |
| -- | all | 命令0-3组合 |
集 TSS_UDP_HOST 和 TSS_UDP_PORT 在 .env 以匹配正在运行的TSS实例。在本地开发过程中,您可以运行TSS2026的本地副本进行测试;在JSC测试周上,指向美国宇航局官方托管的实例。
# Verify connectivity
uv run python test_tss_udp.py文档搜索
将参考文件放在 docs/ (支持子目录)。LLM通过两步工作流程搜索它们:
search_docs("egress procedure")--查找与file:行引用匹配的项read_doc("procedures/ev-team-procedure-timeline.pdf", around_line=42)--读取该匹配的上下文
支持的格式:Markdown、纯文本、PDF(通过PyMuPDF)。图像可以通过以下方式进行分析 inspect_image.
注: docs/ 在...里 .gitignore --用您的任务文档在本地填充它。它没有提交到存储库。
数据流
User -> POST /chat
|
1. Build message list: [system_prompt] + [user messages]
2. If total tokens > 80k -> summarize older conversation history
3. Send to Gemma 4 (with think=True)
4. Model reasons internally (thinking trace logged, not streamed)
5. Model decides: answer directly OR call tools
|-- get_tss_state(scope=eva) -> UDP to TSS2026 -> live JSON
|-- search_docs("oxygen") -> grep over docs/ -> file:line matches
|-- read_doc("procedures.pdf", around_line=42) -> context excerpt
|-- inspect_image("maps/dust-map.png") -> base64 injected into LLM context
6. Tool results fed back -> model generates final answer
|-- If images were injected, base64 is stripped after the LLM responds
| (images exist in context for exactly one inference call)
7. Return response (content only, no thinking trace)上下文摘要
当对话的总令牌计数超过 SUMMARIZE_THRESHOLD (默认80k),较旧的消息会通过LLM自动压缩为单个摘要消息。最近的4条消息始终保持不变。
摘要过程中的图像处理:
- 携带base64图像的消息会在摘要文本中注明(例如,“附加1张图像用于视觉分析”),以便摘要记录参考了视觉参考。
- Base64图像数据为 从不 包含在摘要输入中——仅对文本标签进行摘要。
- 摘要后,最近(未摘要)消息中幸存的任何图像都会被删除,因为LLM已经看到并回应了它们。
即时图像剥离(预摘要):
- LLM处理完图像后,图像会立即从对话历史记录中删除
main.py这意味着base64数据存在于上下文中 一 然后用轻量级的文本注释替换推理调用。一张高分辨率地图(约3900×2900像素)在一个回合内花费约5000个视觉符号,而不是整个对话。
Gemma 4推理
Gemma 4通过Ollama支持本土思维 think=True 参数。SDK会自动分离 message.thinking (内部推理)从 message.content (最终答案)。编排者:
- 通过
think=True在每次聊天通话中 - 在服务器端记录思维轨迹长度
- 从不将思维轨迹流式传输或返回给客户端
测试
# Test TSS2026 UDP connectivity (requires running TSS server)
uv run python test_tss_udp.py
# Quick model test
uv run python -c "
import asyncio
from llm_provider import OllamaProvider
async def test():
p = OllamaProvider(host='http://localhost:11434')
r = await p.chat(model='gemma4:26b', messages=[{'role':'user','content':'Hello'}])
print(f'Content: {r.content}')
print(f'Thinking: {len(r.thinking)} chars' if r.thinking else 'No thinking')
asyncio.run(test())
"安全
- MCP服务器可以公开文件系统访问权限或执行命令。不要将端口13853暴露给不受信任的网络。
- 这
.env文件在.gitignore.
