xcz0 commited on
Commit
965cabb
·
1 Parent(s): c82ffa7

增强 LLM 客户端功能,支持多种推理提供方和错误处理,优化生成 Lean 代码的调用逻辑

Browse files
Files changed (2) hide show
  1. README.md +47 -0
  2. app.py +119 -9
README.md CHANGED
@@ -9,3 +9,50 @@ short_description: 测评大模型完成Lean4证明能力的管道
9
  ---
10
 
11
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  ---
10
 
11
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
12
+
13
+ ## 功能概览
14
+
15
+ 本项目提供一个 Streamlit 页面:输入自然语言数学题 → 调用 Hugging Face Inference 生成 `PLAN:` + 一个 `lean4` 代码块 → 通过 `lake env <repl>` 在内置的 Mathlib 项目中编译验证(无 error 且无 sorry 才算通过)。
16
+
17
+ ## Hugging Face Spaces 配置
18
+
19
+ ### 必需 Secrets
20
+
21
+ - `HF_TOKEN`:调用 Hugging Face Inference 必需。未设置会直接在 UI 中报错并停止。
22
+
23
+ ### 可选 Variables
24
+
25
+ - `HF_MODEL_ID`:要调用的模型 ID。
26
+ - 默认:`deepseek-ai/DeepSeek-Prover-V2-7B`
27
+ - 说明:并非所有模型都支持 HF Serverless Inference 的 `text-generation`/`chat-completion`。如果出现 provider 相关报错,优先尝试换一个确认可用的模型或使用 Endpoint。
28
+
29
+ - `HF_BASE_URL`:自定义 Inference Endpoint Base URL(当你使用专用 Endpoint 时设置)。
30
+ - 用途:绕开 Serverless Inference 对“模型/任务”的限制,稳定性通常更好。
31
+
32
+ - `HF_PROVIDER`:显式指定推理提供方(provider)。
33
+ - 示例:`hf-inference`
34
+ - 说明:不同 `huggingface_hub` 版本/运行环境可用的 provider 可能不同;不确定时可以先不设置。
35
+
36
+ - `LEAN_REPL_BIN`:repl 可执行文件路径。
37
+ - 容器默认:`/app/repl/.lake/build/bin/repl`
38
+ - 一般不需要修改。
39
+
40
+ ## 常见问题(Troubleshooting)
41
+
42
+ ### 1) `StopIteration` / 找不到 provider
43
+
44
+ 这通常表示:当前模型 + 任务(比如 `text-generation`)在你的推理环境里没有可用 provider。你可以:
45
+
46
+ 1. 将 `HF_MODEL_ID` 换成一个已在 Hugging Face Inference 上可用的模型;
47
+ 2. 使用专用 Inference Endpoint:设置 `HF_BASE_URL` 并保证 `HF_TOKEN` 有权限;
48
+ 3. 需要时设置 `HF_PROVIDER`(例如 `hf-inference`)来显式选择 provider。
49
+
50
+ ### 2) 模型输出无法解析(没生成标准代码块)
51
+
52
+ 本项目解析逻辑要求:
53
+
54
+ - 先输出以 `PLAN:` 开头的计划段落;
55
+ - 再输出且仅输出一个 fenced code block,且语言标记为 `lean`/`lean4`。
56
+
57
+ 如果 UI 提示“未能生成标准的 Lean 代码块”,可在页面底部查看模型原始输出并据此调整提示词或更换模型。
58
+
app.py CHANGED
@@ -6,6 +6,108 @@ import os
6
  from huggingface_hub import InferenceClient
7
 
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  def _extract_lean_code_blocks(text: str) -> list[str]:
10
  matches = re.findall(
11
  r"```(?:lean4?|lean)\s*\r?\n(.*?)\r?\n```",
@@ -37,11 +139,11 @@ st.title("Lean 4 证明能力在线测评")
37
  st.markdown("输入自然语言数学题,由 LLM 生成证明并由 Lean 4 编译器实时验证。")
38
 
39
  # 配置 LLM 客户端 (建议在 HF Space 设置中添加 HF_TOKEN 密钥)
40
- client = InferenceClient(api_key=os.environ.get("HF_TOKEN"))
41
-
42
  # 默认模型(可通过环境变量覆盖)
43
  MODEL_ID = os.environ.get("HF_MODEL_ID", "deepseek-ai/DeepSeek-Prover-V2-7B")
44
 
 
 
45
  # 用户输入
46
  nl_problem = st.text_area(
47
  "输入数学问题 (自然语言):", "证明:对于任何实数 x,若 x > 0,则 x + 1/x >= 2。"
@@ -91,13 +193,21 @@ Requirements:
91
  3) The final Lean code must compile with Mathlib. Do NOT use `sorry`.
92
  """.strip()
93
 
94
- gen_text = client.text_generation(
95
- prompt,
96
- model=MODEL_ID,
97
- max_new_tokens=4096,
98
- temperature=0.2,
99
- top_p=0.95,
100
- )
 
 
 
 
 
 
 
 
101
 
102
  plan = _extract_plan(gen_text)
103
  code_blocks = _extract_lean_code_blocks(gen_text)
 
6
  from huggingface_hub import InferenceClient
7
 
8
 
9
+ def _make_inference_client(model_id: str) -> InferenceClient:
10
+ """Create an InferenceClient with broad compatibility across huggingface_hub versions.
11
+
12
+ Supports:
13
+ - HF Serverless Inference via token
14
+ - Custom Inference Endpoint via base_url
15
+ - Optional provider selection via env
16
+
17
+ Env vars:
18
+ - HF_TOKEN (required in this app)
19
+ - HF_BASE_URL (optional): custom endpoint base URL
20
+ - HF_PROVIDER (optional): e.g. "hf-inference"
21
+ """
22
+
23
+ token = os.environ.get("HF_TOKEN")
24
+ base_url = os.environ.get("HF_BASE_URL")
25
+ provider = os.environ.get("HF_PROVIDER")
26
+
27
+ base_kwargs: dict[str, object] = {}
28
+ if base_url:
29
+ base_kwargs["base_url"] = base_url
30
+ if provider:
31
+ base_kwargs["provider"] = provider
32
+
33
+ # Try a few constructor signatures to tolerate different hub versions.
34
+ candidates = [
35
+ {"model": model_id, "token": token, **base_kwargs},
36
+ {"model": model_id, "api_key": token, **base_kwargs},
37
+ {"token": token, **base_kwargs},
38
+ {"api_key": token, **base_kwargs},
39
+ {**base_kwargs},
40
+ ]
41
+
42
+ last_err: Exception | None = None
43
+ for kwargs in candidates:
44
+ filtered = {k: v for k, v in kwargs.items() if v is not None}
45
+ try:
46
+ return InferenceClient(**filtered)
47
+ except TypeError as e:
48
+ last_err = e
49
+ continue
50
+
51
+ # Should be unreachable, but keep a safe fallback.
52
+ if last_err is not None:
53
+ raise last_err
54
+ return InferenceClient()
55
+
56
+
57
+ def _call_llm(client: InferenceClient, prompt: str, model_id: str) -> str:
58
+ """Call the model with robust fallbacks.
59
+
60
+ Primary: text_generation
61
+ Fallback: chat completion (OpenAI-style)
62
+ """
63
+
64
+ # 1) Try text-generation first.
65
+ try:
66
+ return client.text_generation(
67
+ prompt,
68
+ model=model_id,
69
+ max_new_tokens=4096,
70
+ temperature=0.2,
71
+ top_p=0.95,
72
+ )
73
+ except TypeError:
74
+ # Older hub versions may not accept `model=` here if model is set in client.
75
+ return client.text_generation(
76
+ prompt,
77
+ max_new_tokens=4096,
78
+ temperature=0.2,
79
+ top_p=0.95,
80
+ )
81
+ except StopIteration as e:
82
+ # huggingface_hub currently may raise StopIteration when it cannot find
83
+ # a provider for the requested (task, model).
84
+ first_err: Exception = e
85
+ except Exception as e:
86
+ first_err = e
87
+
88
+ # 2) Fallback to chat completion if available.
89
+ try:
90
+ chat = client.chat.completions.create(
91
+ model=model_id,
92
+ messages=[{"role": "user", "content": prompt}],
93
+ max_tokens=4096,
94
+ temperature=0.2,
95
+ top_p=0.95,
96
+ )
97
+ content = chat.choices[0].message.content
98
+ if isinstance(content, str) and content.strip():
99
+ return content
100
+ raise RuntimeError("chat-completion 返回空内容")
101
+ except Exception:
102
+ if isinstance(first_err, StopIteration):
103
+ raise RuntimeError(
104
+ "Hugging Face Inference 未能为该模型找到可用的推理提供方(provider)。"
105
+ ) from first_err
106
+ raise
107
+
108
+ # Note: other exceptions are handled by the caller for better UI reporting.
109
+
110
+
111
  def _extract_lean_code_blocks(text: str) -> list[str]:
112
  matches = re.findall(
113
  r"```(?:lean4?|lean)\s*\r?\n(.*?)\r?\n```",
 
139
  st.markdown("输入自然语言数学题,由 LLM 生成证明并由 Lean 4 编译器实时验证。")
140
 
141
  # 配置 LLM 客户端 (建议在 HF Space 设置中添加 HF_TOKEN 密钥)
 
 
142
  # 默认模型(可通过环境变量覆盖)
143
  MODEL_ID = os.environ.get("HF_MODEL_ID", "deepseek-ai/DeepSeek-Prover-V2-7B")
144
 
145
+ client = _make_inference_client(MODEL_ID)
146
+
147
  # 用户输入
148
  nl_problem = st.text_area(
149
  "输入数学问题 (自然语言):", "证明:对于任何实数 x,若 x > 0,则 x + 1/x >= 2。"
 
193
  3) The final Lean code must compile with Mathlib. Do NOT use `sorry`.
194
  """.strip()
195
 
196
+ try:
197
+ gen_text = _call_llm(client, prompt, MODEL_ID)
198
+ except Exception as e:
199
+ # Provide actionable guidance instead of crashing.
200
+ st.error("调用 Hugging Face Inference 失败。")
201
+ st.write("错误信息:", str(e))
202
+
203
+ st.info(
204
+ "可能原因:该模型不支持 Hugging Face Serverless Inference 的 `text-generation`/`chat-completion`。\n"
205
+ "可选解决方案:\n"
206
+ "1) 在 Space Variables 里设置 `HF_MODEL_ID` 为一个已在 Inference 上可用的模��;\n"
207
+ "2) 使用 Hugging Face Inference Endpoint:设置 `HF_BASE_URL` 指向你的 Endpoint,并确保 `HF_TOKEN` 有权限;\n"
208
+ "3) 如需显式指定 provider,可设置 `HF_PROVIDER`(例如 `hf-inference`)。"
209
+ )
210
+ st.stop()
211
 
212
  plan = _extract_plan(gen_text)
213
  code_blocks = _extract_lean_code_blocks(gen_text)