終端機個人助理系列的三個程式檔 cfg.py、krl.py、tui.py 都放在 src/ 底下。讓它們可以用 pip install 安裝、並產生 lpa 指令的,是專案根目錄的 pyproject.toml。這篇逐段說明它在做什麼。
完整檔案
檔案位置:pyproject.toml
[project]
name = "personal-assistant"
version = "0.1.0"
description = "Personal assistant built on deepagents with a Textual TUI"
requires-python = ">=3.12"
dependencies = [
"deepagents>=0.7.19",
"langchain-openai>=1.6.6",
"langchain-core>=1.6.5",
"langgraph>=1.2.12",
"textual>=8.2.8",
"python-dotenv>=1.2.3",
]
[project.scripts]
lpa = "tui:activate"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
only-include = ["src"]
sources = ["src"]
搭配的專案結構:
personal-assistant/
├── src/
│ ├── cfg.py
│ ├── krl.py
│ └── tui.py
└── pyproject.toml
整個檔案分成四段,下面依序說明。
1. [project]:專案的基本資料
[project]
name = "personal-assistant"
version = "0.1.0"
description = "Personal assistant built on deepagents with a Textual TUI"
requires-python = ">=3.12"
name:套件名稱,也就是pip list和pip uninstall時看到的名字。它和import時用的模組名稱沒有關係,這個專案 import 的是cfg、krl、tui。version:版本號。目前只在本機使用,維持0.1.0就好。requires-python:至少需要 Python 3.12,版本太舊的話pip會直接拒絕安裝。
dependencies:執行時需要的套件
dependencies = [
"deepagents>=0.7.19",
"langchain-openai>=1.6.6",
"langchain-core>=1.6.5",
"langgraph>=1.2.12",
"textual>=8.2.8",
"python-dotenv>=1.2.3",
]
安裝專案時,pip 會自動把這些套件一起裝好。每一個都對應到程式碼裡的 import:
| 套件 | 用在哪裡 |
|---|---|
deepagents | krl.py:create_deep_agent、LocalShellBackend、SummarizationMiddleware |
langchain-openai | krl.py:ChatOpenAI,接相容 OpenAI 格式的模型 API |
langchain-core | krl.py:AIMessage、AIMessageChunk、ToolMessage |
langgraph | krl.py:InMemorySaver、Command |
textual | tui.py:整個終端機介面 |
python-dotenv | cfg.py:dotenv_values 讀取 .env |
>= 表示「至少這個版本」。這些都是程式寫好時測試過的版本,比它舊的版本可能缺少用到的功能。
2. [project.scripts]:產生 lpa 指令
[project.scripts]
lpa = "tui:activate"
這是整個檔案最關鍵的一行,格式是 指令名稱 = "模組:函式"。安裝後,pip 會在環境的 bin/(Windows 是 Scripts\)裡產生一個叫 lpa 的執行檔,內容大致等於:
from tui import activate
activate()
tui.py 最後的 activate() 就是給它呼叫的:
def activate() -> None:
"""啟動 TUI"""
Screen().run()
return
所以在終端機輸入 lpa,等於執行 Screen().run(),Textual 介面就會出現。
3. [build-system]:用哪個工具打包
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
pip 本身不負責打包,它會讀這一段,先安裝 hatchling,再讓 hatchling 把專案打包成可以安裝的格式(wheel)。換成 setuptools 或 poetry-core 也可以,但下一段的設定寫法就會不同。
4. [tool.hatch.build.targets.wheel]:把 src/ 裡的檔案放到最上層
[tool.hatch.build.targets.wheel]
only-include = ["src"]
sources = ["src"]
這兩行讓「沒有套件資料夾」的寫法也能運作:
only-include = ["src"]:只把src/打包進去,workspace/、.env這些東西都不會進入套件。sources = ["src"]:打包時把路徑開頭的src/拿掉。src/tui.py會變成tui.py,裝好後就能直接import tui。
實際打包出來的 wheel 內容如下,三個 .py 檔都在最上層,entry_points.txt 記錄了 lpa 指令:
cfg.py
krl.py
tui.py
personal_assistant-0.1.0.dist-info/METADATA
personal_assistant-0.1.0.dist-info/WHEEL
personal_assistant-0.1.0.dist-info/entry_points.txt
personal_assistant-0.1.0.dist-info/RECORD
[console_scripts]
lpa = tui:activate
這也是為什麼三個檔案之間可以直接寫 from cfg import Profile、from krl import Assistant:裝好之後,它們就是三個獨立的最上層模組。
安裝與使用
在專案根目錄(pyproject.toml 所在的資料夾)執行:
pip install -e .
-e 是可編輯模式(editable):不會複製檔案,而是讓 Python 直接讀 src/ 裡的原始檔,之後修改程式碼就不用重新安裝。只有改了 pyproject.toml(例如新增依賴或改指令名稱)時,才需要再執行一次。
裝好之後,到任何放有 .env 的資料夾執行:
lpa
想自己確認打包結果,可以產生一份 wheel 來看:
pip wheel --no-deps -w dist .
python -m zipfile -l dist/personal_assistant-0.1.0-py3-none-any.whl
不想用的時候,用 name 欄位的名稱移除:
pip uninstall personal-assistant
要注意的地方
cfg、krl、tui 會直接裝成最上層模組,名稱又很短,如果環境裡剛好有其他套件也叫 cfg,兩邊會互相覆蓋。建議用 conda 或 venv 為這個專案建立獨立環境。如果之後打算發佈給別人用,比較穩當的做法是把三個檔案放進一個套件資料夾,例如 src/lpa/,改用 from lpa.cfg import Profile 這種寫法。
想看「把 Textual 介面包成指令」更一般的介紹,可以參考這篇文章。