重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
knowledge-management by groeimetai/snow-flow
npx skills add https://github.com/groeimetai/snow-flow --skill knowledge-management知识管理支持创建、组织和共享知识文章。
知识库 (kb_knowledge_base)
├── 类别 (kb_category)
│ ├── 文章 (kb_knowledge)
│ │ ├── 反馈 (kb_feedback)
│ │ └── 使用记录 (kb_use)
│ └── 文章
└── 类别
└── 文章
| 表 | 用途 |
|---|---|
kb_knowledge_base | 知识库定义 |
kb_knowledge | 知识文章 |
kb_category | 文章类别 |
kb_feedback |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 用户对文章的反馈 |
kb_use | 文章使用情况追踪 |
// 创建知识库文章(仅限 ES5!)
var article = new GlideRecord("kb_knowledge")
article.initialize()
// 基本信息
article.setValue("short_description", "How to Reset Your Password")
article.setValue("kb_knowledge_base", getKnowledgeBaseSysId("IT Knowledge"))
article.setValue("kb_category", getCategorySysId("Self-Service"))
// 内容
article.setValue(
"text",
"<h2>Password Reset Instructions</h2>" +
"<p>Follow these steps to reset your password:</p>" +
"<ol>" +
"<li>Go to the Self-Service Portal</li>" +
'<li>Click "Forgot Password"</li>' +
"<li>Enter your email address</li>" +
"<li>Check your email for reset link</li>" +
"<li>Create a new password</li>" +
"</ol>" +
"<h3>Password Requirements</h3>" +
"<ul>" +
"<li>Minimum 12 characters</li>" +
"<li>At least one uppercase letter</li>" +
"<li>At least one number</li>" +
"<li>At least one special character</li>" +
"</ul>",
)
// 元数据
article.setValue("author", gs.getUserID())
article.setValue("article_type", "text") // text, wiki, html
// 工作流状态
article.setValue("workflow_state", "draft")
article.insert()
// 创建文章并添加附件(仅限 ES5!)
var article = new GlideRecord("kb_knowledge")
article.initialize()
article.setValue("short_description", "VPN Setup Guide")
article.setValue("kb_knowledge_base", kbSysId)
article.setValue("text", "<p>See attached PDF for detailed instructions.</p>")
var articleSysId = article.insert()
// 添加附件
var attachment = new GlideSysAttachment()
attachment.copy("kb_knowledge", templateArticleSysId, "kb_knowledge", articleSysId)
| 状态 | 描述 | 下一状态 |
|---|---|---|
| draft | 初始创建 | review |
| review | 等待审批 | published, draft |
| published | 对用户可见 | retired |
| retired | 不再可见 | published |
| outdated | 需要更新 | draft |
// 提交文章以供审核(仅限 ES5!)
function submitForReview(articleSysId) {
var article = new GlideRecord("kb_knowledge")
if (article.get(articleSysId)) {
// 验证必填字段
if (!article.getValue("short_description")) {
gs.addErrorMessage("Short description is required")
return false
}
if (!article.getValue("text")) {
gs.addErrorMessage("Article content is required")
return false
}
// 更改状态
article.setValue("workflow_state", "review")
article.update()
// 通知审核者
gs.eventQueue("kb.article.review", article, "", "")
return true
}
return false
}
// 发布已批准的文章(仅限 ES5!)
function publishArticle(articleSysId) {
var article = new GlideRecord("kb_knowledge")
if (article.get(articleSysId)) {
// 仅从审核状态发布
if (article.getValue("workflow_state") !== "review") {
gs.addErrorMessage("Article must be in review state")
return false
}
// 设置发布日期
article.setValue("workflow_state", "published")
article.setValue("published", new GlideDateTime())
// 如果配置了,则设置过期时间
var kb = article.kb_knowledge_base.getRefRecord()
var expirationDays = parseInt(kb.getValue("article_expiration_days"), 10)
if (expirationDays > 0) {
var expDate = new GlideDateTime()
expDate.addDaysLocalTime(expirationDays)
article.setValue("valid_to", expDate)
}
article.update()
return true
}
return false
}
// 搜索知识文章(仅限 ES5!)
var KnowledgeSearch = Class.create()
KnowledgeSearch.prototype = {
initialize: function () {},
/**
* 搜索知识文章
* @param {string} query - 搜索查询
* @param {object} options - 搜索选项
*/
search: function (query, options) {
options = options || {}
var results = []
var gr = new GlideRecord("kb_knowledge")
// 仅已发布的文章
gr.addQuery("workflow_state", "published")
gr.addQuery("active", true)
// 有效日期范围
var now = new GlideDateTime()
gr.addNullQuery("valid_to").addOrCondition("valid_to", ">", now)
// 在标题和正文中搜索
var qc = gr.addQuery("short_description", "CONTAINS", query)
qc.addOrCondition("text", "CONTAINS", query)
// 按知识库筛选
if (options.knowledgeBase) {
gr.addQuery("kb_knowledge_base", options.knowledgeBase)
}
// 按类别筛选
if (options.category) {
gr.addQuery("kb_category", options.category)
}
// 限制结果数量
gr.setLimit(options.limit || 10)
// 按浏览量/评分排序
gr.orderByDesc("sys_view_count")
gr.query()
while (gr.next()) {
results.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
title: gr.getValue("short_description"),
category: gr.kb_category.getDisplayValue(),
views: gr.getValue("sys_view_count"),
rating: gr.getValue("rating"),
snippet: this._getSnippet(gr.getValue("text"), query),
})
}
return results
},
_getSnippet: function (text, query) {
// 去除 HTML
var plainText = text.replace(/<[^>]*>/g, "")
// 查找查询位置
var lowerText = plainText.toLowerCase()
var lowerQuery = query.toLowerCase()
var pos = lowerText.indexOf(lowerQuery)
if (pos === -1) {
return plainText.substring(0, 200) + "..."
}
// 提取匹配项周围的上下文
var start = Math.max(0, pos - 50)
var end = Math.min(plainText.length, pos + query.length + 150)
var snippet = ""
if (start > 0) snippet += "..."
snippet += plainText.substring(start, end)
if (end < plainText.length) snippet += "..."
return snippet
},
type: "KnowledgeSearch",
}
// 从模板创建文章(仅限 ES5!)
function createFromTemplate(templateName, data) {
// 获取模板
var template = new GlideRecord("kb_template")
template.addQuery("name", templateName)
template.query()
if (!template.next()) {
gs.error("Template not found: " + templateName)
return null
}
// 创建文章
var article = new GlideRecord("kb_knowledge")
article.initialize()
// 复制模板字段
article.setValue("kb_knowledge_base", template.getValue("kb_knowledge_base"))
article.setValue("kb_category", template.getValue("kb_category"))
article.setValue("article_type", template.getValue("article_type"))
// 使用数据处理模板文本
var text = template.getValue("text")
for (var key in data) {
if (data.hasOwnProperty(key)) {
var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "g")
text = text.replace(pattern, data[key])
}
}
article.setValue("text", text)
article.setValue("short_description", data.title || "New Article")
article.setValue("workflow_state", "draft")
return article.insert()
}
// 用法示例
var articleId = createFromTemplate("Troubleshooting Guide", {
title: "Outlook Not Connecting",
problem: "Outlook shows disconnected",
solution: "Check network connection and restart Outlook",
steps: "<ol><li>Close Outlook</li><li>Check WiFi</li><li>Reopen Outlook</li></ol>",
})
// 记录用户反馈(仅限 ES5!)
function recordFeedback(articleSysId, rating, comments) {
var feedback = new GlideRecord("kb_feedback")
feedback.initialize()
feedback.setValue("article", articleSysId)
feedback.setValue("user", gs.getUserID())
feedback.setValue("rating", rating) // 1-5
feedback.setValue("comments", comments)
feedback.setValue("useful", rating >= 4 ? "yes" : "no")
feedback.insert()
// 更新文章评分
updateArticleRating(articleSysId)
}
function updateArticleRating(articleSysId) {
var ga = new GlideAggregate("kb_feedback")
ga.addQuery("article", articleSysId)
ga.addAggregate("AVG", "rating")
ga.addAggregate("COUNT")
ga.query()
if (ga.next()) {
var avgRating = parseFloat(ga.getAggregate("AVG", "rating"))
var count = parseInt(ga.getAggregate("COUNT"), 10)
var article = new GlideRecord("kb_knowledge")
if (article.get(articleSysId)) {
article.setValue("rating", Math.round(avgRating * 10) / 10)
article.setValue("u_feedback_count", count)
article.update()
}
}
}
| 工具 | 用途 |
|---|---|
snow_knowledge_search | 搜索知识库 |
snow_query_table | 查询 kb_knowledge 表 |
snow_find_artifact | 查找文章 |
snow_execute_script_with_output | 测试知识库脚本 |
// 1. 搜索现有文章
await snow_knowledge_search({
query: "password reset",
limit: 5,
})
// 2. 创建新文章
await snow_execute_script_with_output({
script: `
var article = new GlideRecord('kb_knowledge');
article.initialize();
article.setValue('short_description', 'New Article');
article.setValue('text', '<p>Content here</p>');
article.setValue('workflow_state', 'draft');
gs.info('Created: ' + article.insert());
`,
})
// 3. 查找需要审核的文章
await snow_query_table({
table: "kb_knowledge",
query: "workflow_state=review",
fields: "number,short_description,author,sys_created_on",
})
每周安装量
68
代码仓库
GitHub 星标数
56
首次出现
2026年1月22日
安全审计
安装于
cursor62
codex62
github-copilot62
gemini-cli62
opencode61
kimi-cli57
Knowledge Management enables creating, organizing, and sharing knowledge articles.
Knowledge Base (kb_knowledge_base)
├── Category (kb_category)
│ ├── Article (kb_knowledge)
│ │ ├── Feedback (kb_feedback)
│ │ └── Use (kb_use)
│ └── Article
└── Category
└── Article
| Table | Purpose |
|---|---|
kb_knowledge_base | Knowledge base definitions |
kb_knowledge | Knowledge articles |
kb_category | Article categories |
kb_feedback | User feedback on articles |
kb_use | Article usage tracking |
// Create KB article (ES5 ONLY!)
var article = new GlideRecord("kb_knowledge")
article.initialize()
// Basic info
article.setValue("short_description", "How to Reset Your Password")
article.setValue("kb_knowledge_base", getKnowledgeBaseSysId("IT Knowledge"))
article.setValue("kb_category", getCategorySysId("Self-Service"))
// Content
article.setValue(
"text",
"<h2>Password Reset Instructions</h2>" +
"<p>Follow these steps to reset your password:</p>" +
"<ol>" +
"<li>Go to the Self-Service Portal</li>" +
'<li>Click "Forgot Password"</li>' +
"<li>Enter your email address</li>" +
"<li>Check your email for reset link</li>" +
"<li>Create a new password</li>" +
"</ol>" +
"<h3>Password Requirements</h3>" +
"<ul>" +
"<li>Minimum 12 characters</li>" +
"<li>At least one uppercase letter</li>" +
"<li>At least one number</li>" +
"<li>At least one special character</li>" +
"</ul>",
)
// Metadata
article.setValue("author", gs.getUserID())
article.setValue("article_type", "text") // text, wiki, html
// Workflow state
article.setValue("workflow_state", "draft")
article.insert()
// Create article and add attachment (ES5 ONLY!)
var article = new GlideRecord("kb_knowledge")
article.initialize()
article.setValue("short_description", "VPN Setup Guide")
article.setValue("kb_knowledge_base", kbSysId)
article.setValue("text", "<p>See attached PDF for detailed instructions.</p>")
var articleSysId = article.insert()
// Add attachment
var attachment = new GlideSysAttachment()
attachment.copy("kb_knowledge", templateArticleSysId, "kb_knowledge", articleSysId)
| State | Description | Next States |
|---|---|---|
| draft | Initial creation | review |
| review | Awaiting approval | published, draft |
| published | Visible to users | retired |
| retired | No longer visible | published |
| outdated | Needs update | draft |
// Submit article for review (ES5 ONLY!)
function submitForReview(articleSysId) {
var article = new GlideRecord("kb_knowledge")
if (article.get(articleSysId)) {
// Validate required fields
if (!article.getValue("short_description")) {
gs.addErrorMessage("Short description is required")
return false
}
if (!article.getValue("text")) {
gs.addErrorMessage("Article content is required")
return false
}
// Change state
article.setValue("workflow_state", "review")
article.update()
// Notify reviewers
gs.eventQueue("kb.article.review", article, "", "")
return true
}
return false
}
// Publish approved article (ES5 ONLY!)
function publishArticle(articleSysId) {
var article = new GlideRecord("kb_knowledge")
if (article.get(articleSysId)) {
// Only publish from review state
if (article.getValue("workflow_state") !== "review") {
gs.addErrorMessage("Article must be in review state")
return false
}
// Set publish date
article.setValue("workflow_state", "published")
article.setValue("published", new GlideDateTime())
// Set expiration if configured
var kb = article.kb_knowledge_base.getRefRecord()
var expirationDays = parseInt(kb.getValue("article_expiration_days"), 10)
if (expirationDays > 0) {
var expDate = new GlideDateTime()
expDate.addDaysLocalTime(expirationDays)
article.setValue("valid_to", expDate)
}
article.update()
return true
}
return false
}
// Search knowledge articles (ES5 ONLY!)
var KnowledgeSearch = Class.create()
KnowledgeSearch.prototype = {
initialize: function () {},
/**
* Search knowledge articles
* @param {string} query - Search query
* @param {object} options - Search options
*/
search: function (query, options) {
options = options || {}
var results = []
var gr = new GlideRecord("kb_knowledge")
// Only published articles
gr.addQuery("workflow_state", "published")
gr.addQuery("active", true)
// Valid date range
var now = new GlideDateTime()
gr.addNullQuery("valid_to").addOrCondition("valid_to", ">", now)
// Search in title and body
var qc = gr.addQuery("short_description", "CONTAINS", query)
qc.addOrCondition("text", "CONTAINS", query)
// Filter by knowledge base
if (options.knowledgeBase) {
gr.addQuery("kb_knowledge_base", options.knowledgeBase)
}
// Filter by category
if (options.category) {
gr.addQuery("kb_category", options.category)
}
// Limit results
gr.setLimit(options.limit || 10)
// Order by views/rating
gr.orderByDesc("sys_view_count")
gr.query()
while (gr.next()) {
results.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
title: gr.getValue("short_description"),
category: gr.kb_category.getDisplayValue(),
views: gr.getValue("sys_view_count"),
rating: gr.getValue("rating"),
snippet: this._getSnippet(gr.getValue("text"), query),
})
}
return results
},
_getSnippet: function (text, query) {
// Strip HTML
var plainText = text.replace(/<[^>]*>/g, "")
// Find query position
var lowerText = plainText.toLowerCase()
var lowerQuery = query.toLowerCase()
var pos = lowerText.indexOf(lowerQuery)
if (pos === -1) {
return plainText.substring(0, 200) + "..."
}
// Extract context around match
var start = Math.max(0, pos - 50)
var end = Math.min(plainText.length, pos + query.length + 150)
var snippet = ""
if (start > 0) snippet += "..."
snippet += plainText.substring(start, end)
if (end < plainText.length) snippet += "..."
return snippet
},
type: "KnowledgeSearch",
}
// Create article from template (ES5 ONLY!)
function createFromTemplate(templateName, data) {
// Get template
var template = new GlideRecord("kb_template")
template.addQuery("name", templateName)
template.query()
if (!template.next()) {
gs.error("Template not found: " + templateName)
return null
}
// Create article
var article = new GlideRecord("kb_knowledge")
article.initialize()
// Copy template fields
article.setValue("kb_knowledge_base", template.getValue("kb_knowledge_base"))
article.setValue("kb_category", template.getValue("kb_category"))
article.setValue("article_type", template.getValue("article_type"))
// Process template text with data
var text = template.getValue("text")
for (var key in data) {
if (data.hasOwnProperty(key)) {
var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "g")
text = text.replace(pattern, data[key])
}
}
article.setValue("text", text)
article.setValue("short_description", data.title || "New Article")
article.setValue("workflow_state", "draft")
return article.insert()
}
// Usage
var articleId = createFromTemplate("Troubleshooting Guide", {
title: "Outlook Not Connecting",
problem: "Outlook shows disconnected",
solution: "Check network connection and restart Outlook",
steps: "<ol><li>Close Outlook</li><li>Check WiFi</li><li>Reopen Outlook</li></ol>",
})
// Record user feedback (ES5 ONLY!)
function recordFeedback(articleSysId, rating, comments) {
var feedback = new GlideRecord("kb_feedback")
feedback.initialize()
feedback.setValue("article", articleSysId)
feedback.setValue("user", gs.getUserID())
feedback.setValue("rating", rating) // 1-5
feedback.setValue("comments", comments)
feedback.setValue("useful", rating >= 4 ? "yes" : "no")
feedback.insert()
// Update article rating
updateArticleRating(articleSysId)
}
function updateArticleRating(articleSysId) {
var ga = new GlideAggregate("kb_feedback")
ga.addQuery("article", articleSysId)
ga.addAggregate("AVG", "rating")
ga.addAggregate("COUNT")
ga.query()
if (ga.next()) {
var avgRating = parseFloat(ga.getAggregate("AVG", "rating"))
var count = parseInt(ga.getAggregate("COUNT"), 10)
var article = new GlideRecord("kb_knowledge")
if (article.get(articleSysId)) {
article.setValue("rating", Math.round(avgRating * 10) / 10)
article.setValue("u_feedback_count", count)
article.update()
}
}
}
| Tool | Purpose |
|---|---|
snow_knowledge_search | Search knowledge base |
snow_query_table | Query kb_knowledge |
snow_find_artifact | Find articles |
snow_execute_script_with_output | Test KB scripts |
// 1. Search for existing articles
await snow_knowledge_search({
query: "password reset",
limit: 5,
})
// 2. Create new article
await snow_execute_script_with_output({
script: `
var article = new GlideRecord('kb_knowledge');
article.initialize();
article.setValue('short_description', 'New Article');
article.setValue('text', '<p>Content here</p>');
article.setValue('workflow_state', 'draft');
gs.info('Created: ' + article.insert());
`,
})
// 3. Find articles needing review
await snow_query_table({
table: "kb_knowledge",
query: "workflow_state=review",
fields: "number,short_description,author,sys_created_on",
})
Weekly Installs
68
Repository
GitHub Stars
56
First Seen
Jan 22, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykPass
Installed on
cursor62
codex62
github-copilot62
gemini-cli62
opencode61
kimi-cli57
MCP源管理指南:连接、优先级排序与速率限制处理 | 企业搜索插件
782 周安装