昨天我說我們要用 AI Agent 審查規格書。但「用 AI」有不同的方式:付費 API(Claude、GPT)或本地模型(Ollama)。
我選了本地。原因很簡單:
缺點是速度。本地模型跑 7 億參數需要時間。在我的 Mac 上,第一次分析大概 2 分鐘。但那是一次性的學習成本,之後就快了。
今天我們要做的是:30 秒內讓這套系統跑起來,拿著你寫的規格書,看本地 LLM 能挑出什麼問題。
三行代碼搞定:
# 1. 裝 Ollama(Mac/Windows/Linux,2 分鐘)
# 去 <https://ollama.ai> 下載,一鍵安裝
# 2. 裝模型(Mistral 7B,推薦用這個,快又能用)
ollama pull mistral
# 3. 啟動本地 LLM 服務
ollama serve
看到 Listening on 127.0.0.1:11434 就算成功。這個窗口保持開著。
在另一個終端,建立項目目錄:
mkdir srs-review-agent
cd srs-review-agent
# 建立項目結構
mkdir -p src tests/fixtures
touch src/__init__.py src/main.py src/models.py
touch tests/fixtures/srs_small.md requirements.txt .env
預期結構:
srs-review-agent/
├── src/
│ ├── __init__.py
│ ├── main.py # 核心邏輯(今天寫)
│ └── models.py # 數據模型
├── tests/fixtures/
│ └── srs_small.md # 測試檔案
├── requirements.txt
└── .env
requirements.txt:
langchain==0.2.0
langgraph==0.0.60
ollama==0.6.2
requests==2.31.0
python-dotenv==1.0.0
pydantic==2.5.2
typer==0.9.0
pytest==7.4.3
安裝:
pip install -r requirements.txt
故意設計有問題的規格書。tests/fixtures/srs_small.md:
# 線上筆記系統
## 功能需求
- REQ-2.1.1:系統支持多用戶並行存取
- REQ-2.1.2:每個用戶可建立無限筆記
- REQ-2.2.1:用戶可分享筆記
- REQ-2.2.2:支持三種權限:檢視、編輯、管理
## 性能需求
- REQ-3.1.1:響應時間 < 500ms
- REQ-3.1.2:支持 1000 個並行用戶
## 安全需求
- REQ-4.1.1:所有數據加密存儲
- REQ-4.1.2:系統採用單用戶模式,每次只有一個用戶活動
矛盾在這裡:REQ-2.1.1 說多用戶,REQ-4.1.2 說單用戶。Agent 應該能檢出來。
.env:
OLLAMA_URL=http://localhost:11434
OLLAMA_MODEL=mistral
src/models.py 很簡單,先只有一個結果類:
from dataclasses import dataclass
from typing import Optional
@dataclass
class AnalysisResult:
srs_filename: str
analysis_text: str
model_used: str
timestamp: Optional[str] = None
def __str__(self) -> str:
return f"分析結果 ({self.model_used}): {self.srs_filename}"
src/main.py 是核心。這裡做三件事:
import os
from pathlib import Path
from dotenv import load_dotenv
import requests
import typer
load_dotenv()
app = typer.Typer()
class OllamaAgent:
"""用本地 LLM 分析規格書"""
def __init__(self, model: str = "mistral", ollama_url: str = "<http://localhost:11434>"):
self.model = model
self.ollama_url = ollama_url
self.api_endpoint = f"{ollama_url}/api/generate"
self._verify_connection()
def _verify_connection(self):
"""檢查 Ollama 有沒有在跑、模型有沒有裝"""
try:
response = requests.get(f"{self.ollama_url}/api/tags", timeout=5)
if response.status_code != 200:
raise ConnectionError("Ollama 服務未響應")
data = response.json()
models = [m['name'].split(':')[0] for m in data.get('models', [])]
if self.model not in models:
raise ConnectionError(
f"模型 '{self.model}' 未下載。\n"
f"請執行:ollama pull {self.model}\n"
f"已下載:{', '.join(models) if models else '無'}"
)
print(f"✓ Ollama 連接成功,模型:{self.model}")
except requests.exceptions.ConnectionError:
raise ConnectionError(
"無法連接 Ollama。\n"
"檢查清單:\n"
"1. 安裝 Ollama (<https://ollama.ai>)\n"
"2. 執行 ollama serve\n"
"3. 在另一個終端執行本命令"
)
def read_srs(self, filepath: str) -> str:
"""讀規格書"""
path = Path(filepath)
if not path.exists():
raise FileNotFoundError(f"檔案不存在: {filepath}")
with open(path, 'r', encoding='utf-8') as f:
return f.read()
def analyze_srs(self, srs_text: str) -> str:
"""呼叫 LLM 分析"""
system_prompt = """你是 SRS 審查專家。分析規格書找出:
1. 邏輯矛盾(需求相衝突)
2. 模糊不清的地方
3. 跨需求依賴問題
4. 改進建議
要具體,引用需求編號,說明問題,提建議。"""
prompt = f"{system_prompt}\n\n分析這份規格書:\n\n{srs_text}"
try:
response = requests.post(
self.api_endpoint,
json={
"model": self.model,
"prompt": prompt,
"stream": False,
"temperature": 0.7,
},
timeout=300
)
if response.status_code != 200:
raise RuntimeError(f"LLM 呼叫失敗: {response.text}")
return response.json().get('response', '無法獲取結果')
except requests.exceptions.Timeout:
raise RuntimeError(
f"分析超時。{self.model} 可能比預期慢。"
)
except requests.exceptions.ConnectionError:
raise RuntimeError("無法連接 Ollama。執行:ollama serve")
@app.command()
def analyze(
filepath: str = typer.Argument(
...,
help="規格書路徑"
),
model: str = typer.Option(
"mistral",
"--model",
"-m",
help="使用的模型"
),
verbose: bool = typer.Option(
False,
"--verbose",
"-v",
help="顯示詳細日誌"
)
):
"""分析規格書(使用本地 LLM)
用法:
python -m src.main analyze tests/fixtures/srs_small.md
python -m src.main analyze tests/fixtures/srs_small.md -m llama2 -v
"""
try:
if verbose:
print(f"模型: {model}, Ollama: <http://localhost:11434>")
agent = OllamaAgent(model=model)
filepath_obj = Path(filepath)
if not filepath_obj.exists():
print(f"❌ 檔案不存在: {filepath}")
raise typer.Exit(1)
print(f"📖 讀取: {filepath}")
srs_text = agent.read_srs(filepath)
print(f"✓ {len(srs_text)} 字符, {len(srs_text.split(chr(10)))} 行")
if verbose:
print(f"\n預覽(前 300 字):\n{srs_text[:300]}...\n")
print(f"\n🔍 用 {model} 分析中...")
print("⏳ 等等(30-120 秒,取決於硬件和規格書大小)")
analysis_result = agent.analyze_srs(srs_text)
print("\n" + "=" * 70)
print("✅ 分析結果")
print("=" * 70)
print(analysis_result)
print("=" * 70)
except ConnectionError as e:
print(f"❌ Ollama 連接錯誤: {e}")
raise typer.Exit(1)
except FileNotFoundError as e:
print(f"❌ 檔案錯誤: {e}")
raise typer.Exit(1)
except RuntimeError as e:
print(f"❌ 執行錯誤: {e}")
raise typer.Exit(1)
except Exception as e:
print(f"❌ 未知錯誤: {e}")
if verbose:
import traceback
print(traceback.format_exc())
raise typer.Exit(1)
if __name__ == "__main__":
app()
打開第一個終端,保持 ollama serve 執行。
打開第二個終端,進入專案目錄,執行:
python -m src.main analyze tests/fixtures/srs_small.md
等 30-120 秒。應該看到類似:
✓ Ollama 連接成功,模型:mistral
📖 讀取: tests/fixtures/srs_small.md
✓ 687 字符, 20 行
🔍 用 mistral 分析中...
⏳ 等等(30-120 秒,取決於硬件和規格書大小)
======================================================================
✅ 分析結果
======================================================================
### 發現的矛盾:
1. **多用戶 vs 單用戶衝突**(REQ-2.1.1 vs REQ-4.1.2)
- REQ-2.1.1:「系統支持多用戶並行存取」
- REQ-4.1.2:「系統採用單用戶模式」
- 這兩個需求直接相衝
2. **性能假設問題**
- 單用戶系統為什麼要支持 1000 個並行用戶?
### 建議:
澄清系統目標:多用戶協作或單用戶應用?
======================================================================
成功! 🎉 你的本地 LLM Agent 跑起來了。
「Ollama 服務未響應」
➜ 新開終端,執行 ollama serve,看到 Listening on 127.0.0.1:11434。不要關這個窗口。
「模型 mistral 未下載」
➜ 執行 ollama pull mistral。第一次要幾分鐘,取決於網速。
「分析超時」或「很慢」
➜ 正常。Mistral 7B 在 CPU 上需要時間。
ollama pull neural-chat(也能用,就是回答品質會差一點)「ModuleNotFoundError」
➜ 執行 pip install -r requirements.txt,確保依賴都裝了。
「No module named 'src'」
➜ 檢查你在 srs-review-agent/ 目錄裡執行命令,而且 src/__init__.py 存在(即使是空檔案)。
「我的硬件够嗎?」
Mistral 7B 需要:
今天我們有了一個「會跑」的系統。明天我們把它改成狀態機(用 LangGraph),這樣就能做多步工作流:讀→分塊→提取約束→檢測衝突→生成報告。
現在的 src/main.py 只是一個簡單的函數。明天它會變成有狀態、可追蹤、能改進的 Agent。
代碼已經在你的機器上跑了。下一步就是疊功能。
第 1 週:透明的 SRS 分析