标签: 本地大语言模型 2025-12-03 次
过去一年,北京心玥软件公司的开发人员在遇到的项目中会把工程工作流程里那些重复的琐碎任务转移到了本地大语言模型(LLM)上。这些是每天出现几十次的小杂活,悄悄消耗你的精力。把它们自动化掉真是件好事。
如果你是软件工程师,想去掉繁琐部分、加快速度,那我希望分享我的一些脚本能启发你也理顺自己的工作流程。
我的设置核心是Ollama。它运行几个专注于代码的本地模型。要跑这些参数更高的模型,你机器性能得稍微强点。在我的M4 Mac上,这些模型表现很棒:
• qwen2.5-coder:7b运行极快,对大多数任务来说完全够用。
• qwen2.5-coder:14b稍慢一点,但整体推理和代码质量最好。

本地运行模型的优点是自动保障隐私、即时响应,没有API费用或依赖。非常适合实验和大量使用。
脚本
下面这段代码片段,是我用来自动生成提交信息的Python小脚本。它会从暂存文件里提取差异,调用qwen2.5-coder:14b,生成单行提交信息。我经常提交,这也让大语言模型在小而集中的上下文窗口里更好发挥作用。
#!/usr/bin/env python3
import subprocess
import json
import sys
import requests
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "qwen2.5-coder:14b"
def get_staged_diff():
result = subprocess.run(
["git", "diff", "--cached"],
capture_output=True,
text=True
)
return result.stdout.strip()
def generate_commit_message(diff_text):
payload = {
"model": MODEL,
"prompt": (
"Generate a concise git commit message for this diff. "
"Return ONLY a JSON object containing: {\"message\": \"...\"}.\n\n"
f"Diff:\n{diff_text}"
),
"format": {
"type": "object",
"properties": {
"message": {"type": "string"}
},
"required": ["message"]
},
"stream": False,
"options": {"temperature": "0"}
}
response = requests.post(OLLAMA_URL, json=payload)
response.raise_for_status()
data = response.json()
try:
obj = json.loads(data["response"])
return obj["message"]
except Exception:
print("Error parsing structured output.\nFull response:")
print(data)
sys.exit(1)
def git_commit(message):
subprocess.run(["git", "commit", "-m", message])
def main():
diff = get_staged_diff()
if not diff:
print("No staged changes.")
sys.exit(1)
print("Generating AI commit message...")
message = generate_commit_message(diff)
print(f"\nCommit message:\n{message}\n")
git_commit(message)
print("Committed successfully!")
if __name__ == "__main__":
main()下面这段是另一个Python脚本,用来自动生成PR描述。它会把我的功能分支和基础分支对比,提取差异,发给在Ollama上运行的qwen2.5-coder:14b。模型把技术变更总结成简短、重点突出的PR描述,我再通过GitHub命令行工具发布。我也会读一遍描述,看看模型是否完整抓住了意图——它通常能做到。
#!/usr/bin/env python3
import os
import sys
import subprocess
import re
import json
import requests
import textwrap
import tempfile
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "qwen2.5-coder:14b"
MY_GITHUB_USER = ""
PR_LABELS = []
def run_git(*args) -> str:
result = subprocess.run(
["git", *args],
capture_output=True,
text=True,
)
if result.returncode != 0:
print(f"Error running git {' '.join(args)}:\n{result.stderr}")
sys.exit(1)
return result.stdout.strip()
def get_current_branch() -> str:
return run_git("rev-parse", "--abbrev-ref", "HEAD")
def get_changed_files(base: str, head: str):
out = run_git("diff", "--name-only", f"{base}...{head}")
return [line for line in out.splitlines() if line.strip()]
def get_file_diff(base: str, head: str, path: str) -> str:
result = subprocess.run(
["git", "diff", f"{base}...{head}", "--", path],
capture_output=True,
text=True,
)
return result.stdout.strip()
def generate_description(formatted_changes: str, pr_title: str) -> str:
prompt = textwrap.dedent(f"""
You are helping write the description for a GitHub Pull Request.
PR title:
"{pr_title}"
Below is a formatted list of files and their diffs between the base branch and this feature branch.
Your task:
- Write a concise and short description explaining what this PR does.
- Focus on behavior changes, intent, and key technical points.
- Assume this will go under a heading 'What does this PR do?' already.
- DO NOT include headings, bullet lists, or checkboxes.
- DO NOT mention that you are an AI or describe the process.
- Just output a few sentences or short paragraphs of description.
- Be as short and concise as possible without sacrificing meaning or quality.
Here are the changes:
{formatted_changes}
""")
payload = {
"model": MODEL,
"prompt": prompt,
"stream": False,
"options": {"temperature": 0},
}
response = requests.post(OLLAMA_URL, json=payload)
response.raise_for_status()
data = response.json()
desc = data.get("response", "").strip()
if not desc:
print("Ollama returned an empty description.")
sys.exit(1)
return desc
def create_pr_with_gh_cli(title: str, body: str, base: str = "main"):
with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp:
tmp.write(body)
tmp_path = tmp.name
cmd = [
"gh", "pr", "create",
"--title", title,
"--body-file", tmp_path,
"--base", base,
"--assignee", MY_GITHUB_USER,
]
for label in PR_LABELS:
cmd.extend(["--label", label])
print("Running:", " ".join(cmd))
result = subprocess.run(cmd, text=True)
if result.returncode != 0:
print("gh pr create failed.")
sys.exit(result.returncode)
print("PR created via GitHub CLI.")
def main():
if len(sys.argv) < 2:
print("Usage: ai_github_pr.py \"PR Title\" [--base main]")
sys.exit(1)
args = sys.argv[1:]
base = "main"
if "--base" in args:
idx = args.index("--base")
try:
base = args[idx + 1]
except IndexError:
print("Error: --base requires a branch name argument.")
sys.exit(1)
args = args[:idx] + args[idx + 2:]
raw_title = args[0]
head = get_current_branch()
if not raw_title.startswith(f"[{head}]"):
title = f"[{head}] {raw_title}"
else:
title = raw_title
files = get_changed_files(base, head)
print(files)
if not files:
print(f"No changed files between {base}...{head}.")
sys.exit(1)
chunks = []
for path in files:
diff = get_file_diff(base, head, path)
if not diff:
continue
chunk = f"=== File: {path} ===\n\n{diff}\n\n"
chunks.append(chunk)
formatted_changes = "\n".join(chunks)
if not formatted_changes.strip():
print("No meaningful diffs found to describe.")
sys.exit(1)
print("Generating PR description from Ollama...")
description = generate_description(formatted_changes, title)
template = """#### What does this PR do?
{description}
"""
body = template.format(
description=description,
branch_name=head,
)
print("\n--- Generated PR Body Preview ---\n")
print(body)
print("\n---------------------------------\n")
answer = input("Create PR with this body via gh? [y/N]: ").strip().lower()
if answer not in ("y", "yes"):
print("Aborted.")
sys.exit(0)
create_pr_with_gh_cli(title=title, body=body, base=base)
if __name__ == "__main__":
main()我还用一组Python脚本查询公司定制的“类Jira”系统。它们提取项目细节,把事项分成可执行的任务,嵌入关联的参考资料,再把所有内容汇编成一份“Cursor指令文档”。这些脚本完全按我的工作流程定制,所以这里不分享。
我希望前两个脚本对你有用,毕竟我们很多人工作流程相似。就算不完全适用,也希望至少能启发你把一天中无聊的部分自动化,腾出更多时间做有意义、喜欢的工作。