Skip to content

Commit 099821d

Browse files
committed
基础逻辑完成
1 parent 1679508 commit 099821d

13 files changed

Lines changed: 834 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea

README.md

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,72 @@
1-
# text2sql
2-
将自然语言转换为对应的SQL查询语句
1+
# Text2SQL
2+
3+
一个基于自然语言处理的工具,可以将自然语言转换为对应的SQL查询语句。
4+
5+
## 功能特点
6+
7+
- 支持将中文自然语言转换为SQL查询语句
8+
- 自动验证生成的SQL语句的正确性
9+
- 支持多次重试以提高成功率
10+
- 可选择是否执行生成的SQL语句
11+
12+
## 安装
13+
14+
```bash
15+
go get github.com/wangle201210/text2sql
16+
```
17+
18+
## 使用方法
19+
20+
### 基本用法
21+
22+
```go
23+
package main
24+
25+
import (
26+
"github.com/wangle201210/text2sql"
27+
"fmt"
28+
)
29+
30+
func main() {
31+
client := &text2sql.Text2sql{
32+
DbLink: "root:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local",
33+
Try: 5, // 失败时的重试次数
34+
ShouldRun: true, // 是否执行生成的SQL
35+
}
36+
37+
// 将中文问题转换为SQL并执行
38+
sql, result, err := client.Do("王五的openid")
39+
if err != nil {
40+
panic(err)
41+
}
42+
43+
fmt.Printf("生成的SQL: %s\n", sql)
44+
fmt.Printf("执行结果: %v\n", result)
45+
}
46+
```
47+
48+
### 配置说明
49+
50+
- `DbLink`: MySQL数据库连接信息
51+
- `Try`: SQL生成失败时的重试次数
52+
- `ShouldRun`: 是否执行生成的SQL语句
53+
- 设置为`true`时会执行SQL并返回结果
54+
- 设置为`false`时只返回生成的SQL语句
55+
56+
57+
## 注意事项
58+
59+
1. 确保数据库连接字符串中包含正确的用户名、密码和数据库名
60+
2. 建议在生产环境中适当设置重试次数,避免过多重试
61+
3. 如果只需要生成SQL而不执行,请将`ShouldRun`设置为`false`
62+
4. 用例的数据在[note20250226.sql](./note20250226.sql)
63+
64+
## 依赖
65+
66+
- gorm.io/gorm
67+
- gorm.io/driver/mysql
68+
- github.com/cloudwego/eino
69+
70+
## 许可证
71+
72+
MIT License

eino/eino.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package eino
2+
3+
import (
4+
"context"
5+
)
6+
7+
func GetSQL(ddl, question string) (sql string) {
8+
ctx := context.Background()
9+
messages := createMessagesFromTemplate(ddl, question)
10+
cm := createOpenAIChatModel(ctx)
11+
result := generate(ctx, cm, messages)
12+
sql = result.Content
13+
return
14+
}

eino/generate.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package eino
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
"github.com/cloudwego/eino/components/model"
8+
"github.com/cloudwego/eino/schema"
9+
)
10+
11+
func generate(ctx context.Context, llm model.ChatModel, in []*schema.Message) *schema.Message {
12+
result, err := llm.Generate(ctx, in)
13+
if err != nil {
14+
log.Fatalf("llm generate failed: %v", err)
15+
}
16+
return result
17+
}

eino/message.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package eino
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
"github.com/cloudwego/eino/components/prompt"
8+
"github.com/cloudwego/eino/schema"
9+
)
10+
11+
const (
12+
UnrelatedQuestion = "不相关的问题,请重新提问"
13+
)
14+
15+
func createTemplate() prompt.ChatTemplate {
16+
// 创建模板,使用 FString 格式
17+
return prompt.FromMessages(schema.FString,
18+
// 系统消息模板
19+
schema.SystemMessage("{role}"+
20+
"Given an input question, first create a syntactically correct MySQL query to run, then look at the results of the query and return the answer to the input question."+
21+
"Unless the user specifies in the question a specific number of examples to obtain, query for at most {limit} results using the LIMIT clause as per MySQL. "+
22+
"You can order the results to return the most informative data in the database."+
23+
"Never query for all columns from a table. "+
24+
"You must query only the columns that are needed to answer the question."+
25+
"Wrap each column name in backticks (`) to denote them as delimited identifiers."+
26+
"Pay attention to use only the column names you can see in the tables below. "+
27+
"Be careful to not query for columns that do not exist. "+
28+
"Also, pay attention to which column is in which table."+
29+
"Pay attention to use CURDATE() function to get the current date, if the question involves \"today\"."+
30+
"Can only perform queries and does not accept any modification or deletion functions."+
31+
"Use the following table schema info to create your SQL query:\n{ddl}"+
32+
"返回内容只能包含SQL语句,不包含解释及其他信息也不要加上sql标签。",
33+
// "通过分析用户的提问与数据库表结构之间的关系,生成相应的SQL查询语句。如果提问的内容与现有的数据库表结构没有任何关联,返回:\"{unrelated}\"。",
34+
),
35+
// 插入需要的对话历史(新对话的话这里不填)
36+
schema.MessagesPlaceholder("chat_history", true),
37+
38+
// 用户消息模板
39+
schema.UserMessage("Question: {question}"),
40+
)
41+
}
42+
43+
func createMessagesFromTemplate(ddl, question string) []*schema.Message {
44+
template := createTemplate()
45+
// 使用模板生成消息
46+
messages, err := template.Format(context.Background(), map[string]any{
47+
"role": "You are a MySQL expert.",
48+
// "unrelated": UnrelatedQuestion,
49+
"question": question,
50+
"ddl": ddl,
51+
"limit": 10,
52+
"chat_history": []*schema.Message{},
53+
})
54+
if err != nil {
55+
log.Fatalf("format template failed: %v\n", err)
56+
}
57+
return messages
58+
}

eino/model.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package eino
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
8+
"github.com/cloudwego/eino-ext/components/model/openai"
9+
"github.com/cloudwego/eino/components/model"
10+
)
11+
12+
func createOpenAIChatModel(ctx context.Context) model.ChatModel {
13+
chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
14+
Model: os.Getenv("OPENAI_MODEL_NAME"),
15+
APIKey: os.Getenv("OPENAI_API_KEY"),
16+
BaseURL: os.Getenv("OPENAI_BASE_URL"),
17+
})
18+
if err != nil {
19+
log.Fatalf("create openai chat model failed, err=%v", err)
20+
}
21+
return chatModel
22+
}

go.mod

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module github.com/wangle201210/text2sql
2+
3+
go 1.23.0
4+
5+
require (
6+
github.com/cloudwego/eino v0.3.13
7+
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250225083118-fd27d80f189c
8+
gorm.io/driver/mysql v1.5.7
9+
gorm.io/gorm v1.25.12
10+
)
11+
12+
require (
13+
filippo.io/edwards25519 v1.1.0 // indirect
14+
github.com/bytedance/sonic v1.12.2 // indirect
15+
github.com/bytedance/sonic/loader v0.2.0 // indirect
16+
github.com/cloudwego/base64x v0.1.4 // indirect
17+
github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250221090944-e8ef7aabbe10 // indirect
18+
github.com/cloudwego/iasm v0.2.0 // indirect
19+
github.com/dustin/go-humanize v1.0.1 // indirect
20+
github.com/getkin/kin-openapi v0.118.0 // indirect
21+
github.com/go-openapi/jsonpointer v0.19.5 // indirect
22+
github.com/go-openapi/swag v0.19.5 // indirect
23+
github.com/go-sql-driver/mysql v1.9.0 // indirect
24+
github.com/goph/emperror v0.17.2 // indirect
25+
github.com/invopop/yaml v0.1.0 // indirect
26+
github.com/jinzhu/inflection v1.0.0 // indirect
27+
github.com/jinzhu/now v1.1.5 // indirect
28+
github.com/josharian/intern v1.0.0 // indirect
29+
github.com/json-iterator/go v1.1.12 // indirect
30+
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
31+
github.com/mailru/easyjson v0.7.7 // indirect
32+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
33+
github.com/modern-go/reflect2 v1.0.2 // indirect
34+
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
35+
github.com/nikolalohinski/gonja v1.5.3 // indirect
36+
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
37+
github.com/perimeterx/marshmallow v1.1.4 // indirect
38+
github.com/pkg/errors v0.9.1 // indirect
39+
github.com/sashabaranov/go-openai v1.32.5 // indirect
40+
github.com/sirupsen/logrus v1.9.3 // indirect
41+
github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f // indirect
42+
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
43+
github.com/yargevad/filepathx v1.0.0 // indirect
44+
golang.org/x/arch v0.11.0 // indirect
45+
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
46+
golang.org/x/sys v0.28.0 // indirect
47+
golang.org/x/text v0.22.0 // indirect
48+
gopkg.in/yaml.v2 v2.4.0 // indirect
49+
gopkg.in/yaml.v3 v3.0.1 // indirect
50+
)

0 commit comments

Comments
 (0)